付智勇

no message

正在显示 51 个修改的文件 包含 4413 行增加2 行删除

要显示太多修改。

为保证性能只显示 51 of 51+ 个文件。

@@ -6,12 +6,23 @@ const onerror = require('koa-onerror') @@ -6,12 +6,23 @@ const onerror = require('koa-onerror')
6 const bodyparser = require('koa-bodyparser') 6 const bodyparser = require('koa-bodyparser')
7 const logger = require('koa-logger') 7 const logger = require('koa-logger')
8 const cors = require('koa-cors'); 8 const cors = require('koa-cors');
  9 +const koaBody = require('koa-body');
  10 +const route = require('koa-router');
  11 +
  12 +// app.use(route.post('/profile', uploads.single('avatar')));
  13 +
  14 +
9 15
10 16
11 const index = require('./routes/index') 17 const index = require('./routes/index')
12 const users = require('./routes/users') 18 const users = require('./routes/users')
13 const meeting = require('./routes/meeting') 19 const meeting = require('./routes/meeting')
14 const studentMeeting = require('./routes/studentMeeting') 20 const studentMeeting = require('./routes/studentMeeting')
  21 +const upload = require('./routes/upload')
  22 +const email = require('./routes/email')
  23 +
  24 +
  25 +
15 const filterUrl = require(__dirname+'/util/filterUrl') 26 const filterUrl = require(__dirname+'/util/filterUrl')
16 var tokenUtil = require('./util/tokenUtil'); 27 var tokenUtil = require('./util/tokenUtil');
17 const _ = require('lodash'); 28 const _ = require('lodash');
@@ -20,6 +31,8 @@ var status = require('./util/resTemplate') @@ -20,6 +31,8 @@ var status = require('./util/resTemplate')
20 // error handler 31 // error handler
21 onerror(app) 32 onerror(app)
22 33
  34 +app.use(koaBody({ multipart: true }));
  35 +
23 // middlewares 36 // middlewares
24 app.use(cors()); 37 app.use(cors());
25 app.use(bodyparser({ 38 app.use(bodyparser({
@@ -30,9 +43,11 @@ app.use(logger()) @@ -30,9 +43,11 @@ app.use(logger())
30 app.use(require('koa-static')(__dirname + '/public')) 43 app.use(require('koa-static')(__dirname + '/public'))
31 44
32 app.use(views(__dirname + '/views', { 45 app.use(views(__dirname + '/views', {
33 - extension: 'pug' 46 + extension: 'html'
34 })) 47 }))
35 48
  49 +
  50 +
36 // logger 51 // logger
37 app.use(async (ctx, next) => { 52 app.use(async (ctx, next) => {
38 try{ 53 try{
@@ -60,6 +75,10 @@ app.use(index.routes(), index.allowedMethods()) @@ -60,6 +75,10 @@ app.use(index.routes(), index.allowedMethods())
60 app.use(users.routes(), users.allowedMethods()) 75 app.use(users.routes(), users.allowedMethods())
61 app.use(meeting.routes(), meeting.allowedMethods()) 76 app.use(meeting.routes(), meeting.allowedMethods())
62 app.use(studentMeeting.routes(), studentMeeting.allowedMethods()) 77 app.use(studentMeeting.routes(), studentMeeting.allowedMethods())
  78 +app.use(upload.routes(), upload.allowedMethods())
  79 +app.use(email.routes(), email.allowedMethods())
  80 +
  81 +
63 82
64 83
65 84

32 字节

  1 +../which/bin/which
  1 +# Compiled source #
  2 +###################
  3 +*.com
  4 +*.class
  5 +*.dll
  6 +*.exe
  7 +*.o
  8 +*.so
  9 +
  10 +# Packages #
  11 +############
  12 +# it's better to unpack these files and commit the raw source
  13 +# git has its own built in compression methods
  14 +*.7z
  15 +*.dmg
  16 +*.gz
  17 +*.iso
  18 +*.jar
  19 +*.rar
  20 +*.tar
  21 +*.zip
  22 +
  23 +# Logs and databases #
  24 +######################
  25 +*.log
  26 +*.sql
  27 +*.sqlite
  28 +
  29 +# OS generated files #
  30 +######################
  31 +.DS_Store*
  32 +ehthumbs.db
  33 +Icon?
  34 +Thumbs.db
  35 +
  36 +# Node.js #
  37 +###########
  38 +lib-cov
  39 +*.seed
  40 +*.log
  41 +*.csv
  42 +*.dat
  43 +*.out
  44 +*.pid
  45 +*.gz
  46 +
  47 +pids
  48 +logs
  49 +results
  50 +
  51 +node_modules
  52 +npm-debug.log
  53 +
  54 +# Components #
  55 +##############
  56 +
  57 +/build
  58 +/components
  1 +language: node_js
  2 +node_js:
  3 + - "0.4"
  4 + - "0.6"
  5 + - "0.8"
  6 + - "0.10"
  1 +# Array Series [![Build Status](https://travis-ci.org/component/array-parallel.png)](https://travis-ci.org/component/array-parallel)
  2 +
  3 +Call an array of asynchronous functions in parallel
  4 +
  5 +### API
  6 +
  7 +#### parallel(fns[, context[, callback]])
  8 +
  9 +```js
  10 +var parallel = require('array-parallel')
  11 +
  12 +parallel([
  13 + function (done) {
  14 + done()
  15 + }
  16 +], this, function (err) {
  17 +
  18 +})
  19 +```
  20 +
  21 +#### fns
  22 +
  23 +`fns` is an array of functions to call in parallel.
  24 +The argument signature should be:
  25 +
  26 +```js
  27 +function (done) {
  28 + done(new Error())
  29 + // or
  30 + done(null, result)
  31 +}
  32 +```
  33 +
  34 +That is, each function should only take a `done` as an argument.
  35 +Each callback should only take an `Error` as the first argument,
  36 +or a value as the second.
  37 +
  38 +#### context
  39 +
  40 +Optional context to pass to each `fn`.
  41 +Basically `fn.call(context, done)`.
  42 +
  43 +#### callback(err, results)
  44 +
  45 +```js
  46 +function (err, results) {
  47 +
  48 +}
  49 +```
  50 +
  51 +Only argument is an `Error` argument.
  52 +It will be the first error retrieved from all the `fns`.
  53 +`results` will be an array of results from each `fn`,
  54 +thus this could be considered an asynchronous version of `[].map`.
  55 +
  56 +### License
  57 +
  58 +The MIT License (MIT)
  59 +
  60 +Copyright (c) 2013 Jonathan Ong me@jongleberry.com
  61 +
  62 +Permission is hereby granted, free of charge, to any person obtaining a copy
  63 +of this software and associated documentation files (the "Software"), to deal
  64 +in the Software without restriction, including without limitation the rights
  65 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  66 +copies of the Software, and to permit persons to whom the Software is
  67 +furnished to do so, subject to the following conditions:
  68 +
  69 +The above copyright notice and this permission notice shall be included in
  70 +all copies or substantial portions of the Software.
  71 +
  72 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  73 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  74 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  75 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  76 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  77 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  78 +THE SOFTWARE.
  1 +{
  2 + "name": "array-parallel",
  3 + "description": "Call an array of asynchronous functions in parallel",
  4 + "repo": "array-parallel",
  5 + "version": "0.1.3",
  6 + "main": "index.js",
  7 + "scripts": [
  8 + "index.js"
  9 + ],
  10 + "license": "MIT"
  11 +}
  1 +module.exports = function parallel(fns, context, callback) {
  2 + if (!callback) {
  3 + if (typeof context === 'function') {
  4 + callback = context
  5 + context = null
  6 + } else {
  7 + callback = noop
  8 + }
  9 + }
  10 +
  11 + var pending = fns && fns.length
  12 + if (!pending) return callback(null, []);
  13 +
  14 + var finished = false
  15 + var results = new Array(pending)
  16 +
  17 + fns.forEach(context ? function (fn, i) {
  18 + fn.call(context, maybeDone(i))
  19 + } : function (fn, i) {
  20 + fn(maybeDone(i))
  21 + })
  22 +
  23 + function maybeDone(i) {
  24 + return function (err, result) {
  25 + if (finished) return;
  26 +
  27 + if (err) {
  28 + callback(err, results)
  29 + finished = true
  30 + return
  31 + }
  32 +
  33 + results[i] = result
  34 +
  35 + if (!--pending) callback(null, results);
  36 + }
  37 + }
  38 +}
  39 +
  40 +function noop() {}
  1 +{
  2 + "_args": [
  3 + [
  4 + {
  5 + "raw": "array-parallel@~0.1.3",
  6 + "scope": null,
  7 + "escapedName": "array-parallel",
  8 + "name": "array-parallel",
  9 + "rawSpec": "~0.1.3",
  10 + "spec": ">=0.1.3 <0.2.0",
  11 + "type": "range"
  12 + },
  13 + "/Users/fzy/project/koa2_Sequelize_project/node_modules/gm"
  14 + ]
  15 + ],
  16 + "_from": "array-parallel@>=0.1.3 <0.2.0",
  17 + "_id": "array-parallel@0.1.3",
  18 + "_inCache": true,
  19 + "_location": "/array-parallel",
  20 + "_npmUser": {
  21 + "name": "jongleberry",
  22 + "email": "jonathanrichardong@gmail.com"
  23 + },
  24 + "_npmVersion": "1.3.17",
  25 + "_phantomChildren": {},
  26 + "_requested": {
  27 + "raw": "array-parallel@~0.1.3",
  28 + "scope": null,
  29 + "escapedName": "array-parallel",
  30 + "name": "array-parallel",
  31 + "rawSpec": "~0.1.3",
  32 + "spec": ">=0.1.3 <0.2.0",
  33 + "type": "range"
  34 + },
  35 + "_requiredBy": [
  36 + "/gm"
  37 + ],
  38 + "_resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz",
  39 + "_shasum": "8f785308926ed5aa478c47e64d1b334b6c0c947d",
  40 + "_shrinkwrap": null,
  41 + "_spec": "array-parallel@~0.1.3",
  42 + "_where": "/Users/fzy/project/koa2_Sequelize_project/node_modules/gm",
  43 + "author": {
  44 + "name": "Jonathan Ong",
  45 + "email": "me@jongleberry.com",
  46 + "url": "http://jongleberry.com"
  47 + },
  48 + "bugs": {
  49 + "url": "https://github.com/component/array-parallel/issues",
  50 + "email": "me@jongleberry.com"
  51 + },
  52 + "dependencies": {},
  53 + "description": "Call an array of asynchronous functions in parallel",
  54 + "devDependencies": {},
  55 + "directories": {},
  56 + "dist": {
  57 + "shasum": "8f785308926ed5aa478c47e64d1b334b6c0c947d",
  58 + "tarball": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz"
  59 + },
  60 + "homepage": "https://github.com/component/array-parallel#readme",
  61 + "license": "MIT",
  62 + "maintainers": [
  63 + {
  64 + "name": "jongleberry",
  65 + "email": "jonathanrichardong@gmail.com"
  66 + }
  67 + ],
  68 + "name": "array-parallel",
  69 + "optionalDependencies": {},
  70 + "readme": "# Array Series [![Build Status](https://travis-ci.org/component/array-parallel.png)](https://travis-ci.org/component/array-parallel)\n\nCall an array of asynchronous functions in parallel\n\n### API\n\n#### parallel(fns[, context[, callback]])\n\n```js\nvar parallel = require('array-parallel')\n\nparallel([\n function (done) {\n done()\n }\n], this, function (err) {\n\n})\n```\n\n#### fns\n\n`fns` is an array of functions to call in parallel.\nThe argument signature should be:\n\n```js\nfunction (done) {\n done(new Error())\n // or\n done(null, result)\n}\n```\n\nThat is, each function should only take a `done` as an argument.\nEach callback should only take an `Error` as the first argument,\nor a value as the second.\n\n#### context\n\nOptional context to pass to each `fn`.\nBasically `fn.call(context, done)`.\n\n#### callback(err, results)\n\n```js\nfunction (err, results) {\n\n}\n```\n\nOnly argument is an `Error` argument.\nIt will be the first error retrieved from all the `fns`.\n`results` will be an array of results from each `fn`,\nthus this could be considered an asynchronous version of `[].map`.\n\n### License\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 Jonathan Ong me@jongleberry.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n",
  71 + "readmeFilename": "README.md",
  72 + "repository": {
  73 + "type": "git",
  74 + "url": "git+https://github.com/component/array-parallel.git"
  75 + },
  76 + "scripts": {
  77 + "test": "node test"
  78 + },
  79 + "version": "0.1.3"
  80 +}
  1 +var assert = require('assert')
  2 +var parallel = require('./')
  3 +
  4 +var a, b, c
  5 +parallel([
  6 + function (done) {
  7 + setTimeout(function () {
  8 + done(null, a = 0)
  9 + }, 5)
  10 + },
  11 + function (done) {
  12 + setTimeout(function () {
  13 + done(null, b = 1)
  14 + }, 10)
  15 + },
  16 + function (done) {
  17 + setTimeout(function () {
  18 + done(null, c = 2)
  19 + }, 15)
  20 + }
  21 +], function (err, results) {
  22 + assert.equal(a, 0)
  23 + assert.equal(b, 1)
  24 + assert.equal(c, 2)
  25 +
  26 + assert.deepEqual(results, [0, 1, 2])
  27 +})
  28 +
  29 +var d, e
  30 +parallel([
  31 + function (done) {
  32 + setTimeout(function () {
  33 + d = 1
  34 + done(new Error('message'))
  35 + }, 5)
  36 + },
  37 + function (done) {
  38 + setTimeout(function () {
  39 + e = 2
  40 + done()
  41 + }, 10)
  42 + }
  43 +], function (err) {
  44 + assert.equal(err.message, 'message')
  45 + assert.equal(d, 1)
  46 + assert.equal(e, undefined)
  47 +})
  48 +
  49 +var context = 'hello'
  50 +parallel([function (done) {
  51 + assert.equal(this, context)
  52 +}], context)
  53 +
  54 +var f
  55 +parallel([function (done) {
  56 + f = true
  57 + done()
  58 +}])
  59 +
  60 +process.nextTick(function () {
  61 + assert.equal(f, true)
  62 +})
  1 +# Compiled source #
  2 +###################
  3 +*.com
  4 +*.class
  5 +*.dll
  6 +*.exe
  7 +*.o
  8 +*.so
  9 +
  10 +# Packages #
  11 +############
  12 +# it's better to unpack these files and commit the raw source
  13 +# git has its own built in compression methods
  14 +*.7z
  15 +*.dmg
  16 +*.gz
  17 +*.iso
  18 +*.jar
  19 +*.rar
  20 +*.tar
  21 +*.zip
  22 +
  23 +# Logs and databases #
  24 +######################
  25 +*.log
  26 +*.sql
  27 +*.sqlite
  28 +
  29 +# OS generated files #
  30 +######################
  31 +.DS_Store*
  32 +ehthumbs.db
  33 +Icon?
  34 +Thumbs.db
  35 +
  36 +# Node.js #
  37 +###########
  38 +lib-cov
  39 +*.seed
  40 +*.log
  41 +*.csv
  42 +*.dat
  43 +*.out
  44 +*.pid
  45 +*.gz
  46 +
  47 +pids
  48 +logs
  49 +results
  50 +
  51 +node_modules
  52 +npm-debug.log
  53 +
  54 +# Components #
  55 +##############
  56 +
  57 +/build
  58 +/components
  1 +language: node_js
  2 +node_js:
  3 + - "0.8"
  4 + - "0.10"
  1 +# Array Series [![Build Status](https://travis-ci.org/component/array-series.png)](https://travis-ci.org/component/array-series)
  2 +
  3 +Call an array of asynchronous functions in series
  4 +
  5 +### API
  6 +
  7 +#### series(fns[, context[, callback]])
  8 +
  9 +```js
  10 +var series = require('array-series')
  11 +
  12 +series([
  13 + function (done) {
  14 + done()
  15 + }
  16 +], this, function (err) {
  17 +
  18 +})
  19 +```
  20 +
  21 +#### fns
  22 +
  23 +`fns` is an array of functions to call in series.
  24 +The argument signature should be:
  25 +
  26 +```js
  27 +function (done) {
  28 + done(new Error())
  29 + // or
  30 + done()
  31 +}
  32 +```
  33 +
  34 +That is, each function should only take a `done` as an argument.
  35 +Each callback should only take an optional `Error` as an argument.
  36 +
  37 +#### context
  38 +
  39 +Optional context to pass to each `fn`.
  40 +Basically `fn.call(context, done)`.
  41 +
  42 +#### callback(err)
  43 +
  44 +```js
  45 +function (err) {
  46 +
  47 +}
  48 +```
  49 +
  50 +Only argument is an `Error` argument.
  51 +It will return the first error in the series of functions that returns an error,
  52 +and no function after will be called.
  53 +
  54 +### License
  55 +
  56 +The MIT License (MIT)
  57 +
  58 +Copyright (c) 2013 Jonathan Ong me@jongleberry.com
  59 +
  60 +Permission is hereby granted, free of charge, to any person obtaining a copy
  61 +of this software and associated documentation files (the "Software"), to deal
  62 +in the Software without restriction, including without limitation the rights
  63 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  64 +copies of the Software, and to permit persons to whom the Software is
  65 +furnished to do so, subject to the following conditions:
  66 +
  67 +The above copyright notice and this permission notice shall be included in
  68 +all copies or substantial portions of the Software.
  69 +
  70 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  71 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  72 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  73 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  74 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  75 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  76 +THE SOFTWARE.
  1 +{
  2 + "name": "array-series",
  3 + "description": "Call an array of asynchronous functions in series",
  4 + "repo": "component/array-series",
  5 + "version": "0.1.5",
  6 + "main": "index.js",
  7 + "scripts": [
  8 + "index.js"
  9 + ],
  10 + "license": "MIT"
  11 +}
  1 +module.exports = function series(fns, context, callback) {
  2 + if (!callback) {
  3 + if (typeof context === 'function') {
  4 + callback = context
  5 + context = null
  6 + } else {
  7 + callback = noop
  8 + }
  9 + }
  10 +
  11 + if (!(fns && fns.length)) return callback();
  12 +
  13 + fns = fns.slice(0)
  14 +
  15 + var call = context
  16 + ? function () {
  17 + fns.length
  18 + ? fns.shift().call(context, next)
  19 + : callback()
  20 + }
  21 + : function () {
  22 + fns.length
  23 + ? fns.shift()(next)
  24 + : callback()
  25 + }
  26 +
  27 + call()
  28 +
  29 + function next(err) {
  30 + err ? callback(err) : call()
  31 + }
  32 +}
  33 +
  34 +function noop() {}
  1 +{
  2 + "_args": [
  3 + [
  4 + {
  5 + "raw": "array-series@~0.1.5",
  6 + "scope": null,
  7 + "escapedName": "array-series",
  8 + "name": "array-series",
  9 + "rawSpec": "~0.1.5",
  10 + "spec": ">=0.1.5 <0.2.0",
  11 + "type": "range"
  12 + },
  13 + "/Users/fzy/project/koa2_Sequelize_project/node_modules/gm"
  14 + ]
  15 + ],
  16 + "_from": "array-series@>=0.1.5 <0.2.0",
  17 + "_id": "array-series@0.1.5",
  18 + "_inCache": true,
  19 + "_location": "/array-series",
  20 + "_npmUser": {
  21 + "name": "jongleberry",
  22 + "email": "jonathanrichardong@gmail.com"
  23 + },
  24 + "_npmVersion": "1.3.17",
  25 + "_phantomChildren": {},
  26 + "_requested": {
  27 + "raw": "array-series@~0.1.5",
  28 + "scope": null,
  29 + "escapedName": "array-series",
  30 + "name": "array-series",
  31 + "rawSpec": "~0.1.5",
  32 + "spec": ">=0.1.5 <0.2.0",
  33 + "type": "range"
  34 + },
  35 + "_requiredBy": [
  36 + "/gm"
  37 + ],
  38 + "_resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz",
  39 + "_shasum": "df5d37bfc5c2ef0755e2aa4f92feae7d4b5a972f",
  40 + "_shrinkwrap": null,
  41 + "_spec": "array-series@~0.1.5",
  42 + "_where": "/Users/fzy/project/koa2_Sequelize_project/node_modules/gm",
  43 + "author": {
  44 + "name": "Jonathan Ong",
  45 + "email": "me@jongleberry.com",
  46 + "url": "http://jongleberry.com"
  47 + },
  48 + "bugs": {
  49 + "url": "https://github.com/component/array-series/issues",
  50 + "email": "me@jongleberry.com"
  51 + },
  52 + "dependencies": {},
  53 + "description": "Call an array of asynchronous functions in series",
  54 + "devDependencies": {},
  55 + "directories": {},
  56 + "dist": {
  57 + "shasum": "df5d37bfc5c2ef0755e2aa4f92feae7d4b5a972f",
  58 + "tarball": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz"
  59 + },
  60 + "homepage": "https://github.com/component/array-series#readme",
  61 + "license": "MIT",
  62 + "maintainers": [
  63 + {
  64 + "name": "jongleberry",
  65 + "email": "jonathanrichardong@gmail.com"
  66 + }
  67 + ],
  68 + "name": "array-series",
  69 + "optionalDependencies": {},
  70 + "readme": "# Array Series [![Build Status](https://travis-ci.org/component/array-series.png)](https://travis-ci.org/component/array-series)\n\nCall an array of asynchronous functions in series\n\n### API\n\n#### series(fns[, context[, callback]])\n\n```js\nvar series = require('array-series')\n\nseries([\n function (done) {\n done()\n }\n], this, function (err) {\n\n})\n```\n\n#### fns\n\n`fns` is an array of functions to call in series.\nThe argument signature should be:\n\n```js\nfunction (done) {\n done(new Error())\n // or\n done()\n}\n```\n\nThat is, each function should only take a `done` as an argument.\nEach callback should only take an optional `Error` as an argument.\n\n#### context\n\nOptional context to pass to each `fn`.\nBasically `fn.call(context, done)`.\n\n#### callback(err)\n\n```js\nfunction (err) {\n\n}\n```\n\nOnly argument is an `Error` argument.\nIt will return the first error in the series of functions that returns an error,\nand no function after will be called.\n\n### License\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 Jonathan Ong me@jongleberry.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.",
  71 + "readmeFilename": "README.md",
  72 + "repository": {
  73 + "type": "git",
  74 + "url": "git+https://github.com/component/array-series.git"
  75 + },
  76 + "scripts": {
  77 + "test": "node test"
  78 + },
  79 + "version": "0.1.5"
  80 +}
  1 +var assert = require('assert')
  2 +var series = require('./')
  3 +
  4 +var a, b, c
  5 +
  6 +series([
  7 + function (done) {
  8 + a = 1
  9 + process.nextTick(done)
  10 + check('a')
  11 + },
  12 + function (done) {
  13 + b = 2
  14 + process.nextTick(done)
  15 + check('b')
  16 + },
  17 + function (done) {
  18 + c = 3
  19 + process.nextTick(done)
  20 + check('c')
  21 + }
  22 +], function (err) {
  23 + assert.ifError(err)
  24 + assert.equal(a, 1)
  25 + assert.equal(b, 2)
  26 + assert.equal(c, 3)
  27 +})
  28 +
  29 +function check(x) {
  30 + switch (x) {
  31 + case 'a':
  32 + assert.equal(a, 1)
  33 + assert.equal(b, undefined)
  34 + assert.equal(c, undefined)
  35 + break
  36 + case 'b':
  37 + assert.equal(a, 1)
  38 + assert.equal(b, 2)
  39 + assert.equal(c, undefined)
  40 + break
  41 + case 'c':
  42 + assert.equal(a, 1)
  43 + assert.equal(b, 2)
  44 + assert.equal(c, 3)
  45 + break
  46 + }
  47 +}
  48 +
  49 +var context = 'hello'
  50 +series([function (done) {
  51 + assert.equal(this, context)
  52 + done()
  53 +}], context)
  54 +
  55 +var finished
  56 +series([], function (err) {
  57 + finished = true
  58 +})
  59 +
  60 +process.nextTick(function () {
  61 + if (!finished)
  62 + throw new Error('Failed with no functions.');
  63 +})
  64 +
  65 +var r, d, o
  66 +series([
  67 + function (done) {
  68 + r = 1
  69 + process.nextTick(done)
  70 + },
  71 + function (done) {
  72 + d = 0
  73 + process.nextTick(function () {
  74 + done(new Error('message'))
  75 + })
  76 + },
  77 + function (done) {
  78 + o = 0
  79 + process.nextTick(done)
  80 + }
  81 +], function (err) {
  82 + assert.equal(err.message, 'message')
  83 + assert.equal(r, 1)
  84 + assert.equal(d, 0)
  85 + assert.equal(o, undefined)
  86 +})
  87 +
  88 +console.log('Array series tests pass!')
  1 +Copyright (c) 2014 IndigoUnited
  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 furnished
  8 +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
  19 +THE SOFTWARE.
  1 +# cross-spawn
  2 +
  3 +[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Build status][appveyor-image]][appveyor-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url]
  4 +
  5 +[npm-url]:https://npmjs.org/package/cross-spawn
  6 +[downloads-image]:http://img.shields.io/npm/dm/cross-spawn.svg
  7 +[npm-image]:http://img.shields.io/npm/v/cross-spawn.svg
  8 +[travis-url]:https://travis-ci.org/IndigoUnited/node-cross-spawn
  9 +[travis-image]:http://img.shields.io/travis/IndigoUnited/node-cross-spawn/master.svg
  10 +[appveyor-url]:https://ci.appveyor.com/project/satazor/node-cross-spawn
  11 +[appveyor-image]:https://img.shields.io/appveyor/ci/satazor/node-cross-spawn/master.svg
  12 +[david-dm-url]:https://david-dm.org/IndigoUnited/node-cross-spawn
  13 +[david-dm-image]:https://img.shields.io/david/IndigoUnited/node-cross-spawn.svg
  14 +[david-dm-dev-url]:https://david-dm.org/IndigoUnited/node-cross-spawn#info=devDependencies
  15 +[david-dm-dev-image]:https://img.shields.io/david/dev/IndigoUnited/node-cross-spawn.svg
  16 +
  17 +A cross platform solution to node's spawn and spawnSync.
  18 +
  19 +
  20 +## Installation
  21 +
  22 +`$ npm install cross-spawn`
  23 +
  24 +If you are using `spawnSync` on node 0.10 or older, you will also need to install `spawn-sync`:
  25 +
  26 +`$ npm install spawn-sync`
  27 +
  28 +
  29 +## Why
  30 +
  31 +Node has issues when using spawn on Windows:
  32 +
  33 +- It ignores [PATHEXT](https://github.com/joyent/node/issues/2318)
  34 +- It does not support [shebangs](http://pt.wikipedia.org/wiki/Shebang)
  35 +- It does not allow you to run `del` or `dir`
  36 +- It does not properly escape arguments with spaces or special characters
  37 +
  38 +All these issues are handled correctly by `cross-spawn`.
  39 +There are some known modules, such as [win-spawn](https://github.com/ForbesLindesay/win-spawn), that try to solve this but they are either broken or provide faulty escaping of shell arguments.
  40 +
  41 +
  42 +## Usage
  43 +
  44 +Exactly the same way as node's [`spawn`](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) or [`spawnSync`](https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options), so it's a drop in replacement.
  45 +
  46 +```javascript
  47 +var spawn = require('cross-spawn');
  48 +
  49 +// Spawn NPM asynchronously
  50 +var child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
  51 +
  52 +// Spawn NPM synchronously
  53 +var results = spawn.sync('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
  54 +```
  55 +
  56 +## Caveat
  57 +
  58 +On Windows, cross-spawn will only spawn `cmd.exe` if necessary. If the extension
  59 +of the executable is `.exe` or `.com`, it will spawn it directly. If you wish
  60 +to override this behavior and *always* spawn a shell, pass the `{shell: true}`
  61 +option.
  62 +
  63 +
  64 +## Tests
  65 +
  66 +`$ npm test`
  67 +
  68 +
  69 +## License
  70 +
  71 +Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
  1 +'use strict';
  2 +
  3 +var cp = require('child_process');
  4 +var parse = require('./lib/parse');
  5 +var enoent = require('./lib/enoent');
  6 +
  7 +var cpSpawnSync = cp.spawnSync;
  8 +
  9 +function spawn(command, args, options) {
  10 + var parsed;
  11 + var spawned;
  12 +
  13 + // Parse the arguments
  14 + parsed = parse(command, args, options);
  15 +
  16 + // Spawn the child process
  17 + spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
  18 +
  19 + // Hook into child process "exit" event to emit an error if the command
  20 + // does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
  21 + enoent.hookChildProcess(spawned, parsed);
  22 +
  23 + return spawned;
  24 +}
  25 +
  26 +function spawnSync(command, args, options) {
  27 + var parsed;
  28 + var result;
  29 +
  30 + if (!cpSpawnSync) {
  31 + try {
  32 + cpSpawnSync = require('spawn-sync'); // eslint-disable-line global-require
  33 + } catch (ex) {
  34 + throw new Error(
  35 + 'In order to use spawnSync on node 0.10 or older, you must ' +
  36 + 'install spawn-sync:\n\n' +
  37 + ' npm install spawn-sync --save'
  38 + );
  39 + }
  40 + }
  41 +
  42 + // Parse the arguments
  43 + parsed = parse(command, args, options);
  44 +
  45 + // Spawn the child process
  46 + result = cpSpawnSync(parsed.command, parsed.args, parsed.options);
  47 +
  48 + // Analyze if the command does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
  49 + result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
  50 +
  51 + return result;
  52 +}
  53 +
  54 +module.exports = spawn;
  55 +module.exports.spawn = spawn;
  56 +module.exports.sync = spawnSync;
  57 +
  58 +module.exports._parse = parse;
  59 +module.exports._enoent = enoent;
  1 +'use strict';
  2 +
  3 +var isWin = process.platform === 'win32';
  4 +var resolveCommand = require('./resolveCommand');
  5 +
  6 +var isNode10 = process.version.indexOf('v0.10.') === 0;
  7 +
  8 +function notFoundError(command, syscall) {
  9 + var err;
  10 +
  11 + err = new Error(syscall + ' ' + command + ' ENOENT');
  12 + err.code = err.errno = 'ENOENT';
  13 + err.syscall = syscall + ' ' + command;
  14 +
  15 + return err;
  16 +}
  17 +
  18 +function hookChildProcess(cp, parsed) {
  19 + var originalEmit;
  20 +
  21 + if (!isWin) {
  22 + return;
  23 + }
  24 +
  25 + originalEmit = cp.emit;
  26 + cp.emit = function (name, arg1) {
  27 + var err;
  28 +
  29 + // If emitting "exit" event and exit code is 1, we need to check if
  30 + // the command exists and emit an "error" instead
  31 + // See: https://github.com/IndigoUnited/node-cross-spawn/issues/16
  32 + if (name === 'exit') {
  33 + err = verifyENOENT(arg1, parsed, 'spawn');
  34 +
  35 + if (err) {
  36 + return originalEmit.call(cp, 'error', err);
  37 + }
  38 + }
  39 +
  40 + return originalEmit.apply(cp, arguments);
  41 + };
  42 +}
  43 +
  44 +function verifyENOENT(status, parsed) {
  45 + if (isWin && status === 1 && !parsed.file) {
  46 + return notFoundError(parsed.original, 'spawn');
  47 + }
  48 +
  49 + return null;
  50 +}
  51 +
  52 +function verifyENOENTSync(status, parsed) {
  53 + if (isWin && status === 1 && !parsed.file) {
  54 + return notFoundError(parsed.original, 'spawnSync');
  55 + }
  56 +
  57 + // If we are in node 10, then we are using spawn-sync; if it exited
  58 + // with -1 it probably means that the command does not exist
  59 + if (isNode10 && status === -1) {
  60 + parsed.file = isWin ? parsed.file : resolveCommand(parsed.original);
  61 +
  62 + if (!parsed.file) {
  63 + return notFoundError(parsed.original, 'spawnSync');
  64 + }
  65 + }
  66 +
  67 + return null;
  68 +}
  69 +
  70 +module.exports.hookChildProcess = hookChildProcess;
  71 +module.exports.verifyENOENT = verifyENOENT;
  72 +module.exports.verifyENOENTSync = verifyENOENTSync;
  73 +module.exports.notFoundError = notFoundError;
  1 +'use strict';
  2 +
  3 +module.exports = (function () {
  4 + if (process.platform !== 'win32') {
  5 + return false;
  6 + }
  7 + var nodeVer = process.version.substr(1).split('.').map(function (num) {
  8 + return parseInt(num, 10);
  9 + });
  10 + return (nodeVer[0] === 0 && nodeVer[1] < 12);
  11 +})();
  1 +'use strict';
  2 +
  3 +var fs = require('fs');
  4 +var LRU = require('lru-cache');
  5 +var resolveCommand = require('./resolveCommand');
  6 +var hasBrokenSpawn = require('./hasBrokenSpawn');
  7 +
  8 +var isWin = process.platform === 'win32';
  9 +var shebangCache = new LRU({ max: 50, maxAge: 30 * 1000 }); // Cache just for 30sec
  10 +
  11 +function readShebang(command) {
  12 + var buffer;
  13 + var fd;
  14 + var match;
  15 + var shebang;
  16 +
  17 + // Check if it is in the cache first
  18 + if (shebangCache.has(command)) {
  19 + return shebangCache.get(command);
  20 + }
  21 +
  22 + // Read the first 150 bytes from the file
  23 + buffer = new Buffer(150);
  24 +
  25 + try {
  26 + fd = fs.openSync(command, 'r');
  27 + fs.readSync(fd, buffer, 0, 150, 0);
  28 + fs.closeSync(fd);
  29 + } catch (e) { /* empty */ }
  30 +
  31 + // Check if it is a shebang
  32 + match = buffer.toString().trim().match(/#!(.+)/i);
  33 +
  34 + if (match) {
  35 + shebang = match[1].replace(/\/usr\/bin\/env\s+/i, ''); // Remove /usr/bin/env
  36 + }
  37 +
  38 + // Store the shebang in the cache
  39 + shebangCache.set(command, shebang);
  40 +
  41 + return shebang;
  42 +}
  43 +
  44 +function escapeArg(arg, quote) {
  45 + // Convert to string
  46 + arg = '' + arg;
  47 +
  48 + // If we are not going to quote the argument,
  49 + // escape shell metacharacters, including double and single quotes:
  50 + if (!quote) {
  51 + arg = arg.replace(/([\(\)%!\^<>&|;,"'\s])/g, '^$1');
  52 + } else {
  53 + // Sequence of backslashes followed by a double quote:
  54 + // double up all the backslashes and escape the double quote
  55 + arg = arg.replace(/(\\*)"/g, '$1$1\\"');
  56 +
  57 + // Sequence of backslashes followed by the end of the string
  58 + // (which will become a double quote later):
  59 + // double up all the backslashes
  60 + arg = arg.replace(/(\\*)$/, '$1$1');
  61 +
  62 + // All other backslashes occur literally
  63 +
  64 + // Quote the whole thing:
  65 + arg = '"' + arg + '"';
  66 + }
  67 +
  68 + return arg;
  69 +}
  70 +
  71 +function escapeCommand(command) {
  72 + // Do not escape if this command is not dangerous..
  73 + // We do this so that commands like "echo" or "ifconfig" work
  74 + // Quoting them, will make them unaccessible
  75 + return /^[a-z0-9_-]+$/i.test(command) ? command : escapeArg(command, true);
  76 +}
  77 +
  78 +function requiresShell(command) {
  79 + return !/\.(?:com|exe)$/i.test(command);
  80 +}
  81 +
  82 +function parse(command, args, options) {
  83 + var shebang;
  84 + var applyQuotes;
  85 + var file;
  86 + var original;
  87 + var shell;
  88 +
  89 + // Normalize arguments, similar to nodejs
  90 + if (args && !Array.isArray(args)) {
  91 + options = args;
  92 + args = null;
  93 + }
  94 +
  95 + args = args ? args.slice(0) : []; // Clone array to avoid changing the original
  96 + options = options || {};
  97 + original = command;
  98 +
  99 + if (isWin) {
  100 + // Detect & add support for shebangs
  101 + file = resolveCommand(command);
  102 + file = file || resolveCommand(command, true);
  103 + shebang = file && readShebang(file);
  104 + shell = options.shell || hasBrokenSpawn;
  105 +
  106 + if (shebang) {
  107 + args.unshift(file);
  108 + command = shebang;
  109 + shell = shell || requiresShell(resolveCommand(shebang) || resolveCommand(shebang, true));
  110 + } else {
  111 + shell = shell || requiresShell(file);
  112 + }
  113 +
  114 + if (shell) {
  115 + // Escape command & arguments
  116 + applyQuotes = (command !== 'echo'); // Do not quote arguments for the special "echo" command
  117 + command = escapeCommand(command);
  118 + args = args.map(function (arg) {
  119 + return escapeArg(arg, applyQuotes);
  120 + });
  121 +
  122 + // Use cmd.exe
  123 + args = ['/s', '/c', '"' + command + (args.length ? ' ' + args.join(' ') : '') + '"'];
  124 + command = process.env.comspec || 'cmd.exe';
  125 +
  126 + // Tell node's spawn that the arguments are already escaped
  127 + options.windowsVerbatimArguments = true;
  128 + }
  129 + }
  130 +
  131 + return {
  132 + command: command,
  133 + args: args,
  134 + options: options,
  135 + file: file,
  136 + original: original,
  137 + };
  138 +}
  139 +
  140 +module.exports = parse;
  1 +'use strict';
  2 +
  3 +var path = require('path');
  4 +var which = require('which');
  5 +var LRU = require('lru-cache');
  6 +
  7 +var commandCache = new LRU({ max: 50, maxAge: 30 * 1000 }); // Cache just for 30sec
  8 +
  9 +function resolveCommand(command, noExtension) {
  10 + var resolved;
  11 +
  12 + noExtension = !!noExtension;
  13 + resolved = commandCache.get(command + '!' + noExtension);
  14 +
  15 + // Check if its resolved in the cache
  16 + if (commandCache.has(command)) {
  17 + return commandCache.get(command);
  18 + }
  19 +
  20 + try {
  21 + resolved = !noExtension ?
  22 + which.sync(command) :
  23 + which.sync(command, { pathExt: path.delimiter + (process.env.PATHEXT || '') });
  24 + } catch (e) { /* empty */ }
  25 +
  26 + commandCache.set(command + '!' + noExtension, resolved);
  27 +
  28 + return resolved;
  29 +}
  30 +
  31 +module.exports = resolveCommand;
  1 +{
  2 + "_args": [
  3 + [
  4 + {
  5 + "raw": "cross-spawn@^4.0.0",
  6 + "scope": null,
  7 + "escapedName": "cross-spawn",
  8 + "name": "cross-spawn",
  9 + "rawSpec": "^4.0.0",
  10 + "spec": ">=4.0.0 <5.0.0",
  11 + "type": "range"
  12 + },
  13 + "/Users/fzy/project/koa2_Sequelize_project/node_modules/gm"
  14 + ]
  15 + ],
  16 + "_from": "cross-spawn@>=4.0.0 <5.0.0",
  17 + "_id": "cross-spawn@4.0.2",
  18 + "_inCache": true,
  19 + "_location": "/cross-spawn",
  20 + "_nodeVersion": "4.5.0",
  21 + "_npmOperationalInternal": {
  22 + "host": "packages-12-west.internal.npmjs.com",
  23 + "tmp": "tmp/cross-spawn-4.0.2.tgz_1474803799646_0.017929385183379054"
  24 + },
  25 + "_npmUser": {
  26 + "name": "satazor",
  27 + "email": "andremiguelcruz@msn.com"
  28 + },
  29 + "_npmVersion": "2.15.9",
  30 + "_phantomChildren": {},
  31 + "_requested": {
  32 + "raw": "cross-spawn@^4.0.0",
  33 + "scope": null,
  34 + "escapedName": "cross-spawn",
  35 + "name": "cross-spawn",
  36 + "rawSpec": "^4.0.0",
  37 + "spec": ">=4.0.0 <5.0.0",
  38 + "type": "range"
  39 + },
  40 + "_requiredBy": [
  41 + "/gm"
  42 + ],
  43 + "_resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
  44 + "_shasum": "7b9247621c23adfdd3856004a823cbe397424d41",
  45 + "_shrinkwrap": null,
  46 + "_spec": "cross-spawn@^4.0.0",
  47 + "_where": "/Users/fzy/project/koa2_Sequelize_project/node_modules/gm",
  48 + "author": {
  49 + "name": "IndigoUnited",
  50 + "email": "hello@indigounited.com",
  51 + "url": "http://indigounited.com"
  52 + },
  53 + "bugs": {
  54 + "url": "https://github.com/IndigoUnited/node-cross-spawn/issues/"
  55 + },
  56 + "dependencies": {
  57 + "lru-cache": "^4.0.1",
  58 + "which": "^1.2.9"
  59 + },
  60 + "description": "Cross platform child_process#spawn and child_process#spawnSync",
  61 + "devDependencies": {
  62 + "@satazor/eslint-config": "^3.0.0",
  63 + "eslint": "^3.0.0",
  64 + "expect.js": "^0.3.0",
  65 + "glob": "^7.0.0",
  66 + "mkdirp": "^0.5.1",
  67 + "mocha": "^3.0.2",
  68 + "rimraf": "^2.5.0"
  69 + },
  70 + "directories": {},
  71 + "dist": {
  72 + "shasum": "7b9247621c23adfdd3856004a823cbe397424d41",
  73 + "tarball": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz"
  74 + },
  75 + "files": [
  76 + "index.js",
  77 + "lib"
  78 + ],
  79 + "gitHead": "674ceb2f2b69ad64b5dcad661b9bf048d6ec4c22",
  80 + "homepage": "https://github.com/IndigoUnited/node-cross-spawn#readme",
  81 + "keywords": [
  82 + "spawn",
  83 + "spawnSync",
  84 + "windows",
  85 + "cross",
  86 + "platform",
  87 + "path",
  88 + "ext",
  89 + "path-ext",
  90 + "path_ext",
  91 + "shebang",
  92 + "hashbang",
  93 + "cmd",
  94 + "execute"
  95 + ],
  96 + "license": "MIT",
  97 + "main": "index.js",
  98 + "maintainers": [
  99 + {
  100 + "name": "satazor",
  101 + "email": "andremiguelcruz@msn.com"
  102 + }
  103 + ],
  104 + "name": "cross-spawn",
  105 + "optionalDependencies": {},
  106 + "readme": "# cross-spawn\n\n[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Build status][appveyor-image]][appveyor-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url]\n\n[npm-url]:https://npmjs.org/package/cross-spawn\n[downloads-image]:http://img.shields.io/npm/dm/cross-spawn.svg\n[npm-image]:http://img.shields.io/npm/v/cross-spawn.svg\n[travis-url]:https://travis-ci.org/IndigoUnited/node-cross-spawn\n[travis-image]:http://img.shields.io/travis/IndigoUnited/node-cross-spawn/master.svg\n[appveyor-url]:https://ci.appveyor.com/project/satazor/node-cross-spawn\n[appveyor-image]:https://img.shields.io/appveyor/ci/satazor/node-cross-spawn/master.svg\n[david-dm-url]:https://david-dm.org/IndigoUnited/node-cross-spawn\n[david-dm-image]:https://img.shields.io/david/IndigoUnited/node-cross-spawn.svg\n[david-dm-dev-url]:https://david-dm.org/IndigoUnited/node-cross-spawn#info=devDependencies\n[david-dm-dev-image]:https://img.shields.io/david/dev/IndigoUnited/node-cross-spawn.svg\n\nA cross platform solution to node's spawn and spawnSync.\n\n\n## Installation\n\n`$ npm install cross-spawn`\n\nIf you are using `spawnSync` on node 0.10 or older, you will also need to install `spawn-sync`:\n\n`$ npm install spawn-sync`\n\n\n## Why\n\nNode has issues when using spawn on Windows:\n\n- It ignores [PATHEXT](https://github.com/joyent/node/issues/2318)\n- It does not support [shebangs](http://pt.wikipedia.org/wiki/Shebang)\n- It does not allow you to run `del` or `dir`\n- It does not properly escape arguments with spaces or special characters\n\nAll these issues are handled correctly by `cross-spawn`.\nThere are some known modules, such as [win-spawn](https://github.com/ForbesLindesay/win-spawn), that try to solve this but they are either broken or provide faulty escaping of shell arguments.\n\n\n## Usage\n\nExactly the same way as node's [`spawn`](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) or [`spawnSync`](https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options), so it's a drop in replacement.\n\n```javascript\nvar spawn = require('cross-spawn');\n\n// Spawn NPM asynchronously\nvar child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });\n\n// Spawn NPM synchronously\nvar results = spawn.sync('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });\n```\n\n## Caveat\n\nOn Windows, cross-spawn will only spawn `cmd.exe` if necessary. If the extension\nof the executable is `.exe` or `.com`, it will spawn it directly. If you wish\nto override this behavior and *always* spawn a shell, pass the `{shell: true}`\noption.\n\n\n## Tests\n\n`$ npm test`\n\n\n## License\n\nReleased under the [MIT License](http://www.opensource.org/licenses/mit-license.php).\n",
  107 + "readmeFilename": "README.md",
  108 + "repository": {
  109 + "type": "git",
  110 + "url": "git://github.com/IndigoUnited/node-cross-spawn.git"
  111 + },
  112 + "scripts": {
  113 + "lint": "eslint '{*.js,lib/**/*.js,test/**/*.js}'",
  114 + "test": "node test/prepare && mocha --bail test/test"
  115 + },
  116 + "version": "4.0.2"
  117 +}
1 -Copyright (c) 2012-2014 Raynos. 1 +The MIT License (MIT)
  2 +
  3 +Copyright (c) 2014-2015, Jon Schlinkert.
2 4
3 Permission is hereby granted, free of charge, to any person obtaining a copy 5 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 6 of this software and associated documentation files (the "Software"), to deal
  1 +# extend-shallow [![NPM version](https://badge.fury.io/js/extend-shallow.svg)](http://badge.fury.io/js/extend-shallow) [![Build Status](https://travis-ci.org/jonschlinkert/extend-shallow.svg)](https://travis-ci.org/jonschlinkert/extend-shallow)
  2 +
  3 +> Extend an object with the properties of additional objects. node.js/javascript util.
  4 +
  5 +## Install
  6 +
  7 +Install with [npm](https://www.npmjs.com/)
  8 +
  9 +```sh
  10 +$ npm i extend-shallow --save
  11 +```
  12 +
  13 +## Usage
  14 +
  15 +```js
  16 +var extend = require('extend-shallow');
  17 +
  18 +extend({a: 'b'}, {c: 'd'})
  19 +//=> {a: 'b', c: 'd'}
  20 +```
  21 +
  22 +Pass an empty object to shallow clone:
  23 +
  24 +```js
  25 +var obj = {};
  26 +extend(obj, {a: 'b'}, {c: 'd'})
  27 +//=> {a: 'b', c: 'd'}
  28 +```
  29 +
  30 +## Related
  31 +
  32 +* [extend-shallow](https://github.com/jonschlinkert/extend-shallow): Extend an object with the properties of additional objects. node.js/javascript util.
  33 +* [for-own](https://github.com/jonschlinkert/for-own): Iterate over the own enumerable properties of an object, and return an object with properties… [more](https://github.com/jonschlinkert/for-own)
  34 +* [for-in](https://github.com/jonschlinkert/for-in): Iterate over the own and inherited enumerable properties of an objecte, and return an object… [more](https://github.com/jonschlinkert/for-in)
  35 +* [is-plain-object](https://github.com/jonschlinkert/is-plain-object): Returns true if an object was created by the `Object` constructor.
  36 +* [isobject](https://github.com/jonschlinkert/isobject): Returns true if the value is an object and not an array or null.
  37 +* [kind-of](https://github.com/jonschlinkert/kind-of): Get the native type of a value.
  38 +
  39 +## Running tests
  40 +
  41 +Install dev dependencies:
  42 +
  43 +```sh
  44 +$ npm i -d && npm test
  45 +```
  46 +
  47 +## Author
  48 +
  49 +**Jon Schlinkert**
  50 +
  51 ++ [github/jonschlinkert](https://github.com/jonschlinkert)
  52 ++ [twitter/jonschlinkert](http://twitter.com/jonschlinkert)
  53 +
  54 +## License
  55 +
  56 +Copyright © 2015 Jon Schlinkert
  57 +Released under the MIT license.
  58 +
  59 +***
  60 +
  61 +_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on June 29, 2015._
  1 +'use strict';
  2 +
  3 +var isObject = require('is-extendable');
  4 +
  5 +module.exports = function extend(o/*, objects*/) {
  6 + if (!isObject(o)) { o = {}; }
  7 +
  8 + var len = arguments.length;
  9 + for (var i = 1; i < len; i++) {
  10 + var obj = arguments[i];
  11 +
  12 + if (isObject(obj)) {
  13 + assign(o, obj);
  14 + }
  15 + }
  16 + return o;
  17 +};
  18 +
  19 +function assign(a, b) {
  20 + for (var key in b) {
  21 + if (hasOwn(b, key)) {
  22 + a[key] = b[key];
  23 + }
  24 + }
  25 +}
  26 +
  27 +/**
  28 + * Returns true if the given `key` is an own property of `obj`.
  29 + */
  30 +
  31 +function hasOwn(obj, key) {
  32 + return Object.prototype.hasOwnProperty.call(obj, key);
  33 +}
  1 +{
  2 + "_args": [
  3 + [
  4 + {
  5 + "raw": "extend-shallow@^2.0.1",
  6 + "scope": null,
  7 + "escapedName": "extend-shallow",
  8 + "name": "extend-shallow",
  9 + "rawSpec": "^2.0.1",
  10 + "spec": ">=2.0.1 <3.0.0",
  11 + "type": "range"
  12 + },
  13 + "/Users/fzy/project/koa2_Sequelize_project/node_modules/koa-better-body"
  14 + ]
  15 + ],
  16 + "_from": "extend-shallow@>=2.0.1 <3.0.0",
  17 + "_id": "extend-shallow@2.0.1",
  18 + "_inCache": true,
  19 + "_location": "/extend-shallow",
  20 + "_nodeVersion": "0.12.4",
  21 + "_npmUser": {
  22 + "name": "jonschlinkert",
  23 + "email": "github@sellside.com"
  24 + },
  25 + "_npmVersion": "2.10.1",
  26 + "_phantomChildren": {},
  27 + "_requested": {
  28 + "raw": "extend-shallow@^2.0.1",
  29 + "scope": null,
  30 + "escapedName": "extend-shallow",
  31 + "name": "extend-shallow",
  32 + "rawSpec": "^2.0.1",
  33 + "spec": ">=2.0.1 <3.0.0",
  34 + "type": "range"
  35 + },
  36 + "_requiredBy": [
  37 + "/koa-better-body"
  38 + ],
  39 + "_resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
  40 + "_shasum": "51af7d614ad9a9f610ea1bafbb989d6b1c56890f",
  41 + "_shrinkwrap": null,
  42 + "_spec": "extend-shallow@^2.0.1",
  43 + "_where": "/Users/fzy/project/koa2_Sequelize_project/node_modules/koa-better-body",
  44 + "author": {
  45 + "name": "Jon Schlinkert",
  46 + "url": "https://github.com/jonschlinkert"
  47 + },
  48 + "bugs": {
  49 + "url": "https://github.com/jonschlinkert/extend-shallow/issues"
  50 + },
  51 + "dependencies": {
  52 + "is-extendable": "^0.1.0"
  53 + },
  54 + "description": "Extend an object with the properties of additional objects. node.js/javascript util.",
  55 + "devDependencies": {
  56 + "array-slice": "^0.2.3",
  57 + "benchmarked": "^0.1.4",
  58 + "chalk": "^1.0.0",
  59 + "for-own": "^0.1.3",
  60 + "glob": "^5.0.12",
  61 + "is-plain-object": "^2.0.1",
  62 + "kind-of": "^2.0.0",
  63 + "minimist": "^1.1.1",
  64 + "mocha": "^2.2.5",
  65 + "should": "^7.0.1"
  66 + },
  67 + "directories": {},
  68 + "dist": {
  69 + "shasum": "51af7d614ad9a9f610ea1bafbb989d6b1c56890f",
  70 + "tarball": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz"
  71 + },
  72 + "engines": {
  73 + "node": ">=0.10.0"
  74 + },
  75 + "files": [
  76 + "index.js"
  77 + ],
  78 + "gitHead": "e9b1f1d2ff9d2990ec4a127afa7c14732d1eec8a",
  79 + "homepage": "https://github.com/jonschlinkert/extend-shallow",
  80 + "keywords": [
  81 + "assign",
  82 + "extend",
  83 + "javascript",
  84 + "js",
  85 + "keys",
  86 + "merge",
  87 + "obj",
  88 + "object",
  89 + "prop",
  90 + "properties",
  91 + "property",
  92 + "props",
  93 + "shallow",
  94 + "util",
  95 + "utility",
  96 + "utils",
  97 + "value"
  98 + ],
  99 + "license": "MIT",
  100 + "main": "index.js",
  101 + "maintainers": [
  102 + {
  103 + "name": "jonschlinkert",
  104 + "email": "github@sellside.com"
  105 + }
  106 + ],
  107 + "name": "extend-shallow",
  108 + "optionalDependencies": {},
  109 + "readme": "# extend-shallow [![NPM version](https://badge.fury.io/js/extend-shallow.svg)](http://badge.fury.io/js/extend-shallow) [![Build Status](https://travis-ci.org/jonschlinkert/extend-shallow.svg)](https://travis-ci.org/jonschlinkert/extend-shallow)\n\n> Extend an object with the properties of additional objects. node.js/javascript util.\n\n## Install\n\nInstall with [npm](https://www.npmjs.com/)\n\n```sh\n$ npm i extend-shallow --save\n```\n\n## Usage\n\n```js\nvar extend = require('extend-shallow');\n\nextend({a: 'b'}, {c: 'd'})\n//=> {a: 'b', c: 'd'}\n```\n\nPass an empty object to shallow clone:\n\n```js\nvar obj = {};\nextend(obj, {a: 'b'}, {c: 'd'})\n//=> {a: 'b', c: 'd'}\n```\n\n## Related\n\n* [extend-shallow](https://github.com/jonschlinkert/extend-shallow): Extend an object with the properties of additional objects. node.js/javascript util.\n* [for-own](https://github.com/jonschlinkert/for-own): Iterate over the own enumerable properties of an object, and return an object with properties… [more](https://github.com/jonschlinkert/for-own)\n* [for-in](https://github.com/jonschlinkert/for-in): Iterate over the own and inherited enumerable properties of an objecte, and return an object… [more](https://github.com/jonschlinkert/for-in)\n* [is-plain-object](https://github.com/jonschlinkert/is-plain-object): Returns true if an object was created by the `Object` constructor.\n* [isobject](https://github.com/jonschlinkert/isobject): Returns true if the value is an object and not an array or null.\n* [kind-of](https://github.com/jonschlinkert/kind-of): Get the native type of a value.\n\n## Running tests\n\nInstall dev dependencies:\n\n```sh\n$ npm i -d && npm test\n```\n\n## Author\n\n**Jon Schlinkert**\n\n+ [github/jonschlinkert](https://github.com/jonschlinkert)\n+ [twitter/jonschlinkert](http://twitter.com/jonschlinkert)\n\n## License\n\nCopyright © 2015 Jon Schlinkert\nReleased under the MIT license.\n\n***\n\n_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on June 29, 2015._",
  110 + "readmeFilename": "README.md",
  111 + "repository": {
  112 + "type": "git",
  113 + "url": "git+https://github.com/jonschlinkert/extend-shallow.git"
  114 + },
  115 + "scripts": {
  116 + "test": "mocha"
  117 + },
  118 + "version": "2.0.1"
  119 +}
  1 +/test
  2 +/tool
  3 +/example
  4 +/benchmark
  5 +*.upload
  6 +*.un~
  7 +*.http
  1 +language: node_js
  2 +node_js:
  3 + - 4
  4 + - 6
  5 + - 7
  1 +Copyright (C) 2011 Felix Geisendörfer
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  4 +
  5 +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  6 +
  7 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  1 +# Formidable
  2 +
  3 +[![Build Status](https://travis-ci.org/felixge/node-formidable.svg?branch=master)](https://travis-ci.org/felixge/node-formidable)
  4 +
  5 +## Purpose
  6 +
  7 +A Node.js module for parsing form data, especially file uploads.
  8 +
  9 +## Current status
  10 +
  11 +**Maintainers Wanted:** Please see https://github.com/felixge/node-formidable/issues/412
  12 +
  13 +This module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading
  14 +and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from
  15 +a large variety of clients and is considered production-ready.
  16 +
  17 +## Features
  18 +
  19 +* Fast (~500mb/sec), non-buffering multipart parser
  20 +* Automatically writing file uploads to disk
  21 +* Low memory footprint
  22 +* Graceful error handling
  23 +* Very high test coverage
  24 +
  25 +## Installation
  26 +
  27 +```sh
  28 +npm i -S formidable
  29 +```
  30 +
  31 +This is a low level package, and if you're using a high level framework such as Express, chances are it's already included in it. You can [read this discussion](http://stackoverflow.com/questions/11295554/how-to-disable-express-bodyparser-for-file-uploads-node-js) about how Formidable is integrated with Express.
  32 +
  33 +Note: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library.
  34 +
  35 +## Example
  36 +
  37 +Parse an incoming file upload.
  38 +```javascript
  39 +var formidable = require('formidable'),
  40 + http = require('http'),
  41 + util = require('util');
  42 +
  43 +http.createServer(function(req, res) {
  44 + if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
  45 + // parse a file upload
  46 + var form = new formidable.IncomingForm();
  47 +
  48 + form.parse(req, function(err, fields, files) {
  49 + res.writeHead(200, {'content-type': 'text/plain'});
  50 + res.write('received upload:\n\n');
  51 + res.end(util.inspect({fields: fields, files: files}));
  52 + });
  53 +
  54 + return;
  55 + }
  56 +
  57 + // show a file upload form
  58 + res.writeHead(200, {'content-type': 'text/html'});
  59 + res.end(
  60 + '<form action="/upload" enctype="multipart/form-data" method="post">'+
  61 + '<input type="text" name="title"><br>'+
  62 + '<input type="file" name="upload" multiple="multiple"><br>'+
  63 + '<input type="submit" value="Upload">'+
  64 + '</form>'
  65 + );
  66 +}).listen(8080);
  67 +```
  68 +## API
  69 +
  70 +### Formidable.IncomingForm
  71 +```javascript
  72 +var form = new formidable.IncomingForm()
  73 +```
  74 +Creates a new incoming form.
  75 +
  76 +```javascript
  77 +form.encoding = 'utf-8';
  78 +```
  79 +Sets encoding for incoming form fields.
  80 +
  81 +```javascript
  82 +form.uploadDir = "/my/dir";
  83 +```
  84 +Sets the directory for placing file uploads in. You can move them later on using
  85 +`fs.rename()`. The default is `os.tmpdir()`.
  86 +
  87 +```javascript
  88 +form.keepExtensions = false;
  89 +```
  90 +If you want the files written to `form.uploadDir` to include the extensions of the original files, set this property to `true`.
  91 +
  92 +```javascript
  93 +form.type
  94 +```
  95 +Either 'multipart' or 'urlencoded' depending on the incoming request.
  96 +
  97 +```javascript
  98 +form.maxFieldsSize = 2 * 1024 * 1024;
  99 +```
  100 +Limits the amount of memory all fields together (except files) can allocate in bytes.
  101 +If this value is exceeded, an `'error'` event is emitted. The default
  102 +size is 2MB.
  103 +
  104 +```javascript
  105 +form.maxFields = 1000;
  106 +```
  107 +Limits the number of fields that the querystring parser will decode. Defaults
  108 +to 1000 (0 for unlimited).
  109 +
  110 +```javascript
  111 +form.hash = false;
  112 +```
  113 +If you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`.
  114 +
  115 +```javascript
  116 +form.multiples = false;
  117 +```
  118 +If this option is enabled, when you call `form.parse`, the `files` argument will contain arrays of files for inputs which submit multiple files using the HTML5 `multiple` attribute.
  119 +
  120 +```javascript
  121 +form.bytesReceived
  122 +```
  123 +The amount of bytes received for this form so far.
  124 +
  125 +```javascript
  126 +form.bytesExpected
  127 +```
  128 +The expected number of bytes in this form.
  129 +
  130 +```javascript
  131 +form.parse(request, [cb]);
  132 +```
  133 +Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields and files are collected and passed to the callback:
  134 +
  135 +
  136 +```javascript
  137 +form.parse(req, function(err, fields, files) {
  138 + // ...
  139 +});
  140 +
  141 +form.onPart(part);
  142 +```
  143 +You may overwrite this method if you are interested in directly accessing the multipart stream. Doing so will disable any `'field'` / `'file'` events processing which would occur otherwise, making you fully responsible for handling the processing.
  144 +
  145 +```javascript
  146 +form.onPart = function(part) {
  147 + part.addListener('data', function() {
  148 + // ...
  149 + });
  150 +}
  151 +```
  152 +If you want to use formidable to only handle certain parts for you, you can do so:
  153 +```javascript
  154 +form.onPart = function(part) {
  155 + if (!part.filename) {
  156 + // let formidable handle all non-file parts
  157 + form.handlePart(part);
  158 + }
  159 +}
  160 +```
  161 +Check the code in this method for further inspiration.
  162 +
  163 +
  164 +### Formidable.File
  165 +```javascript
  166 +file.size = 0
  167 +```
  168 +The size of the uploaded file in bytes. If the file is still being uploaded (see `'fileBegin'` event), this property says how many bytes of the file have been written to disk yet.
  169 +```javascript
  170 +file.path = null
  171 +```
  172 +The path this file is being written to. You can modify this in the `'fileBegin'` event in
  173 +case you are unhappy with the way formidable generates a temporary path for your files.
  174 +```javascript
  175 +file.name = null
  176 +```
  177 +The name this file had according to the uploading client.
  178 +```javascript
  179 +file.type = null
  180 +```
  181 +The mime type of this file, according to the uploading client.
  182 +```javascript
  183 +file.lastModifiedDate = null
  184 +```
  185 +A date object (or `null`) containing the time this file was last written to. Mostly
  186 +here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).
  187 +```javascript
  188 +file.hash = null
  189 +```
  190 +If hash calculation was set, you can read the hex digest out of this var.
  191 +
  192 +#### Formidable.File#toJSON()
  193 +
  194 + This method returns a JSON-representation of the file, allowing you to
  195 + `JSON.stringify()` the file which is useful for logging and responding
  196 + to requests.
  197 +
  198 +### Events
  199 +
  200 +
  201 +#### 'progress'
  202 +
  203 +Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.
  204 +
  205 +```javascript
  206 +form.on('progress', function(bytesReceived, bytesExpected) {
  207 +});
  208 +```
  209 +
  210 +
  211 +
  212 +#### 'field'
  213 +
  214 +Emitted whenever a field / value pair has been received.
  215 +
  216 +```javascript
  217 +form.on('field', function(name, value) {
  218 +});
  219 +```
  220 +
  221 +#### 'fileBegin'
  222 +
  223 +Emitted whenever a new file is detected in the upload stream. Use this event if
  224 +you want to stream the file to somewhere else while buffering the upload on
  225 +the file system.
  226 +
  227 +```javascript
  228 +form.on('fileBegin', function(name, file) {
  229 +});
  230 +```
  231 +
  232 +#### 'file'
  233 +
  234 +Emitted whenever a field / file pair has been received. `file` is an instance of `File`.
  235 +
  236 +```javascript
  237 +form.on('file', function(name, file) {
  238 +});
  239 +```
  240 +
  241 +#### 'error'
  242 +
  243 +Emitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call `request.resume()` if you want the request to continue firing `'data'` events.
  244 +
  245 +```javascript
  246 +form.on('error', function(err) {
  247 +});
  248 +```
  249 +
  250 +#### 'aborted'
  251 +
  252 +
  253 +Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. After this event is emitted, an `error` event will follow. In the future there will be a separate 'timeout' event (needs a change in the node core).
  254 +```javascript
  255 +form.on('aborted', function() {
  256 +});
  257 +```
  258 +
  259 +##### 'end'
  260 +```javascript
  261 +form.on('end', function() {
  262 +});
  263 +```
  264 +Emitted when the entire request has been received, and all contained files have finished flushing to disk. This is a great place for you to send your response.
  265 +
  266 +
  267 +
  268 +## Changelog
  269 +
  270 +### v1.1.1 (2017-01-15)
  271 +
  272 + * Fix DeprecationWarning about os.tmpDir() (Christian)
  273 + * Update `buffer.write` order of arguments for Node 7 (Kornel Lesiński)
  274 + * JSON Parser emits error events to the IncomingForm (alessio.montagnani)
  275 + * Improved Content-Disposition parsing (Sebastien)
  276 + * Access WriteStream of fs during runtime instead of include time (Jonas Amundsen)
  277 + * Use built-in toString to convert buffer to hex (Charmander)
  278 + * Add hash to json if present (Nick Stamas)
  279 + * Add license to package.json (Simen Bekkhus)
  280 +
  281 +### v1.0.14 (2013-05-03)
  282 +
  283 +* Add failing hash tests. (Ben Trask)
  284 +* Enable hash calculation again (Eugene Girshov)
  285 +* Test for immediate data events (Tim Smart)
  286 +* Re-arrange IncomingForm#parse (Tim Smart)
  287 +
  288 +### v1.0.13
  289 +
  290 +* Only update hash if update method exists (Sven Lito)
  291 +* According to travis v0.10 needs to go quoted (Sven Lito)
  292 +* Bumping build node versions (Sven Lito)
  293 +* Additional fix for empty requests (Eugene Girshov)
  294 +* Change the default to 1000, to match the new Node behaviour. (OrangeDog)
  295 +* Add ability to control maxKeys in the querystring parser. (OrangeDog)
  296 +* Adjust test case to work with node 0.9.x (Eugene Girshov)
  297 +* Update package.json (Sven Lito)
  298 +* Path adjustment according to eb4468b (Markus Ast)
  299 +
  300 +### v1.0.12
  301 +
  302 +* Emit error on aborted connections (Eugene Girshov)
  303 +* Add support for empty requests (Eugene Girshov)
  304 +* Fix name/filename handling in Content-Disposition (jesperp)
  305 +* Tolerate malformed closing boundary in multipart (Eugene Girshov)
  306 +* Ignore preamble in multipart messages (Eugene Girshov)
  307 +* Add support for application/json (Mike Frey, Carlos Rodriguez)
  308 +* Add support for Base64 encoding (Elmer Bulthuis)
  309 +* Add File#toJSON (TJ Holowaychuk)
  310 +* Remove support for Node.js 0.4 & 0.6 (Andrew Kelley)
  311 +* Documentation improvements (Sven Lito, Andre Azevedo)
  312 +* Add support for application/octet-stream (Ion Lupascu, Chris Scribner)
  313 +* Use os.tmpdir() to get tmp directory (Andrew Kelley)
  314 +* Improve package.json (Andrew Kelley, Sven Lito)
  315 +* Fix benchmark script (Andrew Kelley)
  316 +* Fix scope issue in incoming_forms (Sven Lito)
  317 +* Fix file handle leak on error (OrangeDog)
  318 +
  319 +## License
  320 +
  321 +Formidable is licensed under the MIT license.
  322 +
  323 +## Ports
  324 +
  325 +* [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++ parser based on formidable
  326 +
  327 +## Credits
  328 +
  329 +* [Ryan Dahl](http://twitter.com/ryah) for his work on [http-parser](http://github.com/ry/http-parser) which heavily inspired multipart_parser.js
  1 +module.exports = require('./lib');
  1 +if (global.GENTLY) require = GENTLY.hijack(require);
  2 +
  3 +var util = require('util'),
  4 + fs = require('fs'),
  5 + EventEmitter = require('events').EventEmitter,
  6 + crypto = require('crypto');
  7 +
  8 +function File(properties) {
  9 + EventEmitter.call(this);
  10 +
  11 + this.size = 0;
  12 + this.path = null;
  13 + this.name = null;
  14 + this.type = null;
  15 + this.hash = null;
  16 + this.lastModifiedDate = null;
  17 +
  18 + this._writeStream = null;
  19 +
  20 + for (var key in properties) {
  21 + this[key] = properties[key];
  22 + }
  23 +
  24 + if(typeof this.hash === 'string') {
  25 + this.hash = crypto.createHash(properties.hash);
  26 + } else {
  27 + this.hash = null;
  28 + }
  29 +}
  30 +module.exports = File;
  31 +util.inherits(File, EventEmitter);
  32 +
  33 +File.prototype.open = function() {
  34 + this._writeStream = new fs.WriteStream(this.path);
  35 +};
  36 +
  37 +File.prototype.toJSON = function() {
  38 + var json = {
  39 + size: this.size,
  40 + path: this.path,
  41 + name: this.name,
  42 + type: this.type,
  43 + mtime: this.lastModifiedDate,
  44 + length: this.length,
  45 + filename: this.filename,
  46 + mime: this.mime
  47 + };
  48 + if (this.hash && this.hash != "") {
  49 + json.hash = this.hash;
  50 + }
  51 + return json;
  52 +};
  53 +
  54 +File.prototype.write = function(buffer, cb) {
  55 + var self = this;
  56 + if (self.hash) {
  57 + self.hash.update(buffer);
  58 + }
  59 + this._writeStream.write(buffer, function() {
  60 + self.lastModifiedDate = new Date();
  61 + self.size += buffer.length;
  62 + self.emit('progress', self.size);
  63 + cb();
  64 + });
  65 +};
  66 +
  67 +File.prototype.end = function(cb) {
  68 + var self = this;
  69 + if (self.hash) {
  70 + self.hash = self.hash.digest('hex');
  71 + }
  72 + this._writeStream.end(function() {
  73 + self.emit('end');
  74 + cb();
  75 + });
  76 +};
  1 +if (global.GENTLY) require = GENTLY.hijack(require);
  2 +
  3 +var crypto = require('crypto');
  4 +var fs = require('fs');
  5 +var util = require('util'),
  6 + path = require('path'),
  7 + File = require('./file'),
  8 + MultipartParser = require('./multipart_parser').MultipartParser,
  9 + QuerystringParser = require('./querystring_parser').QuerystringParser,
  10 + OctetParser = require('./octet_parser').OctetParser,
  11 + JSONParser = require('./json_parser').JSONParser,
  12 + StringDecoder = require('string_decoder').StringDecoder,
  13 + EventEmitter = require('events').EventEmitter,
  14 + Stream = require('stream').Stream,
  15 + os = require('os');
  16 +
  17 +function IncomingForm(opts) {
  18 + if (!(this instanceof IncomingForm)) return new IncomingForm(opts);
  19 + EventEmitter.call(this);
  20 +
  21 + opts=opts||{};
  22 +
  23 + this.error = null;
  24 + this.ended = false;
  25 +
  26 + this.maxFields = opts.maxFields || 1000;
  27 + this.maxFieldsSize = opts.maxFieldsSize || 2 * 1024 * 1024;
  28 + this.keepExtensions = opts.keepExtensions || false;
  29 + this.uploadDir = opts.uploadDir || (os.tmpdir && os.tmpdir()) || os.tmpDir();
  30 + this.encoding = opts.encoding || 'utf-8';
  31 + this.headers = null;
  32 + this.type = null;
  33 + this.hash = opts.hash || false;
  34 + this.multiples = opts.multiples || false;
  35 +
  36 + this.bytesReceived = null;
  37 + this.bytesExpected = null;
  38 +
  39 + this._parser = null;
  40 + this._flushing = 0;
  41 + this._fieldsSize = 0;
  42 + this.openedFiles = [];
  43 +
  44 + return this;
  45 +}
  46 +util.inherits(IncomingForm, EventEmitter);
  47 +exports.IncomingForm = IncomingForm;
  48 +
  49 +IncomingForm.prototype.parse = function(req, cb) {
  50 + this.pause = function() {
  51 + try {
  52 + req.pause();
  53 + } catch (err) {
  54 + // the stream was destroyed
  55 + if (!this.ended) {
  56 + // before it was completed, crash & burn
  57 + this._error(err);
  58 + }
  59 + return false;
  60 + }
  61 + return true;
  62 + };
  63 +
  64 + this.resume = function() {
  65 + try {
  66 + req.resume();
  67 + } catch (err) {
  68 + // the stream was destroyed
  69 + if (!this.ended) {
  70 + // before it was completed, crash & burn
  71 + this._error(err);
  72 + }
  73 + return false;
  74 + }
  75 +
  76 + return true;
  77 + };
  78 +
  79 + // Setup callback first, so we don't miss anything from data events emitted
  80 + // immediately.
  81 + if (cb) {
  82 + var fields = {}, files = {};
  83 + this
  84 + .on('field', function(name, value) {
  85 + fields[name] = value;
  86 + })
  87 + .on('file', function(name, file) {
  88 + if (this.multiples) {
  89 + if (files[name]) {
  90 + if (!Array.isArray(files[name])) {
  91 + files[name] = [files[name]];
  92 + }
  93 + files[name].push(file);
  94 + } else {
  95 + files[name] = file;
  96 + }
  97 + } else {
  98 + files[name] = file;
  99 + }
  100 + })
  101 + .on('error', function(err) {
  102 + cb(err, fields, files);
  103 + })
  104 + .on('end', function() {
  105 + cb(null, fields, files);
  106 + });
  107 + }
  108 +
  109 + // Parse headers and setup the parser, ready to start listening for data.
  110 + this.writeHeaders(req.headers);
  111 +
  112 + // Start listening for data.
  113 + var self = this;
  114 + req
  115 + .on('error', function(err) {
  116 + self._error(err);
  117 + })
  118 + .on('aborted', function() {
  119 + self.emit('aborted');
  120 + self._error(new Error('Request aborted'));
  121 + })
  122 + .on('data', function(buffer) {
  123 + self.write(buffer);
  124 + })
  125 + .on('end', function() {
  126 + if (self.error) {
  127 + return;
  128 + }
  129 +
  130 + var err = self._parser.end();
  131 + if (err) {
  132 + self._error(err);
  133 + }
  134 + });
  135 +
  136 + return this;
  137 +};
  138 +
  139 +IncomingForm.prototype.writeHeaders = function(headers) {
  140 + this.headers = headers;
  141 + this._parseContentLength();
  142 + this._parseContentType();
  143 +};
  144 +
  145 +IncomingForm.prototype.write = function(buffer) {
  146 + if (this.error) {
  147 + return;
  148 + }
  149 + if (!this._parser) {
  150 + this._error(new Error('uninitialized parser'));
  151 + return;
  152 + }
  153 +
  154 + this.bytesReceived += buffer.length;
  155 + this.emit('progress', this.bytesReceived, this.bytesExpected);
  156 +
  157 + var bytesParsed = this._parser.write(buffer);
  158 + if (bytesParsed !== buffer.length) {
  159 + this._error(new Error('parser error, '+bytesParsed+' of '+buffer.length+' bytes parsed'));
  160 + }
  161 +
  162 + return bytesParsed;
  163 +};
  164 +
  165 +IncomingForm.prototype.pause = function() {
  166 + // this does nothing, unless overwritten in IncomingForm.parse
  167 + return false;
  168 +};
  169 +
  170 +IncomingForm.prototype.resume = function() {
  171 + // this does nothing, unless overwritten in IncomingForm.parse
  172 + return false;
  173 +};
  174 +
  175 +IncomingForm.prototype.onPart = function(part) {
  176 + // this method can be overwritten by the user
  177 + this.handlePart(part);
  178 +};
  179 +
  180 +IncomingForm.prototype.handlePart = function(part) {
  181 + var self = this;
  182 +
  183 + if (part.filename === undefined) {
  184 + var value = ''
  185 + , decoder = new StringDecoder(this.encoding);
  186 +
  187 + part.on('data', function(buffer) {
  188 + self._fieldsSize += buffer.length;
  189 + if (self._fieldsSize > self.maxFieldsSize) {
  190 + self._error(new Error('maxFieldsSize exceeded, received '+self._fieldsSize+' bytes of field data'));
  191 + return;
  192 + }
  193 + value += decoder.write(buffer);
  194 + });
  195 +
  196 + part.on('end', function() {
  197 + self.emit('field', part.name, value);
  198 + });
  199 + return;
  200 + }
  201 +
  202 + this._flushing++;
  203 +
  204 + var file = new File({
  205 + path: this._uploadPath(part.filename),
  206 + name: part.filename,
  207 + type: part.mime,
  208 + hash: self.hash
  209 + });
  210 +
  211 + this.emit('fileBegin', part.name, file);
  212 +
  213 + file.open();
  214 + this.openedFiles.push(file);
  215 +
  216 + part.on('data', function(buffer) {
  217 + if (buffer.length == 0) {
  218 + return;
  219 + }
  220 + self.pause();
  221 + file.write(buffer, function() {
  222 + self.resume();
  223 + });
  224 + });
  225 +
  226 + part.on('end', function() {
  227 + file.end(function() {
  228 + self._flushing--;
  229 + self.emit('file', part.name, file);
  230 + self._maybeEnd();
  231 + });
  232 + });
  233 +};
  234 +
  235 +function dummyParser(self) {
  236 + return {
  237 + end: function () {
  238 + self.ended = true;
  239 + self._maybeEnd();
  240 + return null;
  241 + }
  242 + };
  243 +}
  244 +
  245 +IncomingForm.prototype._parseContentType = function() {
  246 + if (this.bytesExpected === 0) {
  247 + this._parser = dummyParser(this);
  248 + return;
  249 + }
  250 +
  251 + if (!this.headers['content-type']) {
  252 + this._error(new Error('bad content-type header, no content-type'));
  253 + return;
  254 + }
  255 +
  256 + if (this.headers['content-type'].match(/octet-stream/i)) {
  257 + this._initOctetStream();
  258 + return;
  259 + }
  260 +
  261 + if (this.headers['content-type'].match(/urlencoded/i)) {
  262 + this._initUrlencoded();
  263 + return;
  264 + }
  265 +
  266 + if (this.headers['content-type'].match(/multipart/i)) {
  267 + var m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i);
  268 + if (m) {
  269 + this._initMultipart(m[1] || m[2]);
  270 + } else {
  271 + this._error(new Error('bad content-type header, no multipart boundary'));
  272 + }
  273 + return;
  274 + }
  275 +
  276 + if (this.headers['content-type'].match(/json/i)) {
  277 + this._initJSONencoded();
  278 + return;
  279 + }
  280 +
  281 + this._error(new Error('bad content-type header, unknown content-type: '+this.headers['content-type']));
  282 +};
  283 +
  284 +IncomingForm.prototype._error = function(err) {
  285 + if (this.error || this.ended) {
  286 + return;
  287 + }
  288 +
  289 + this.error = err;
  290 + this.emit('error', err);
  291 +
  292 + if (Array.isArray(this.openedFiles)) {
  293 + this.openedFiles.forEach(function(file) {
  294 + file._writeStream.destroy();
  295 + setTimeout(fs.unlink, 0, file.path, function(error) { });
  296 + });
  297 + }
  298 +};
  299 +
  300 +IncomingForm.prototype._parseContentLength = function() {
  301 + this.bytesReceived = 0;
  302 + if (this.headers['content-length']) {
  303 + this.bytesExpected = parseInt(this.headers['content-length'], 10);
  304 + } else if (this.headers['transfer-encoding'] === undefined) {
  305 + this.bytesExpected = 0;
  306 + }
  307 +
  308 + if (this.bytesExpected !== null) {
  309 + this.emit('progress', this.bytesReceived, this.bytesExpected);
  310 + }
  311 +};
  312 +
  313 +IncomingForm.prototype._newParser = function() {
  314 + return new MultipartParser();
  315 +};
  316 +
  317 +IncomingForm.prototype._initMultipart = function(boundary) {
  318 + this.type = 'multipart';
  319 +
  320 + var parser = new MultipartParser(),
  321 + self = this,
  322 + headerField,
  323 + headerValue,
  324 + part;
  325 +
  326 + parser.initWithBoundary(boundary);
  327 +
  328 + parser.onPartBegin = function() {
  329 + part = new Stream();
  330 + part.readable = true;
  331 + part.headers = {};
  332 + part.name = null;
  333 + part.filename = null;
  334 + part.mime = null;
  335 +
  336 + part.transferEncoding = 'binary';
  337 + part.transferBuffer = '';
  338 +
  339 + headerField = '';
  340 + headerValue = '';
  341 + };
  342 +
  343 + parser.onHeaderField = function(b, start, end) {
  344 + headerField += b.toString(self.encoding, start, end);
  345 + };
  346 +
  347 + parser.onHeaderValue = function(b, start, end) {
  348 + headerValue += b.toString(self.encoding, start, end);
  349 + };
  350 +
  351 + parser.onHeaderEnd = function() {
  352 + headerField = headerField.toLowerCase();
  353 + part.headers[headerField] = headerValue;
  354 +
  355 + // matches either a quoted-string or a token (RFC 2616 section 19.5.1)
  356 + var m = headerValue.match(/\bname=("([^"]*)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))/i);
  357 + if (headerField == 'content-disposition') {
  358 + if (m) {
  359 + part.name = m[2] || m[3] || '';
  360 + }
  361 +
  362 + part.filename = self._fileName(headerValue);
  363 + } else if (headerField == 'content-type') {
  364 + part.mime = headerValue;
  365 + } else if (headerField == 'content-transfer-encoding') {
  366 + part.transferEncoding = headerValue.toLowerCase();
  367 + }
  368 +
  369 + headerField = '';
  370 + headerValue = '';
  371 + };
  372 +
  373 + parser.onHeadersEnd = function() {
  374 + switch(part.transferEncoding){
  375 + case 'binary':
  376 + case '7bit':
  377 + case '8bit':
  378 + parser.onPartData = function(b, start, end) {
  379 + part.emit('data', b.slice(start, end));
  380 + };
  381 +
  382 + parser.onPartEnd = function() {
  383 + part.emit('end');
  384 + };
  385 + break;
  386 +
  387 + case 'base64':
  388 + parser.onPartData = function(b, start, end) {
  389 + part.transferBuffer += b.slice(start, end).toString('ascii');
  390 +
  391 + /*
  392 + four bytes (chars) in base64 converts to three bytes in binary
  393 + encoding. So we should always work with a number of bytes that
  394 + can be divided by 4, it will result in a number of buytes that
  395 + can be divided vy 3.
  396 + */
  397 + var offset = parseInt(part.transferBuffer.length / 4, 10) * 4;
  398 + part.emit('data', new Buffer(part.transferBuffer.substring(0, offset), 'base64'));
  399 + part.transferBuffer = part.transferBuffer.substring(offset);
  400 + };
  401 +
  402 + parser.onPartEnd = function() {
  403 + part.emit('data', new Buffer(part.transferBuffer, 'base64'));
  404 + part.emit('end');
  405 + };
  406 + break;
  407 +
  408 + default:
  409 + return self._error(new Error('unknown transfer-encoding'));
  410 + }
  411 +
  412 + self.onPart(part);
  413 + };
  414 +
  415 +
  416 + parser.onEnd = function() {
  417 + self.ended = true;
  418 + self._maybeEnd();
  419 + };
  420 +
  421 + this._parser = parser;
  422 +};
  423 +
  424 +IncomingForm.prototype._fileName = function(headerValue) {
  425 + // matches either a quoted-string or a token (RFC 2616 section 19.5.1)
  426 + var m = headerValue.match(/\bfilename=("(.*?)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))($|;\s)/i);
  427 + if (!m) return;
  428 +
  429 + var match = m[2] || m[3] || '';
  430 + var filename = match.substr(match.lastIndexOf('\\') + 1);
  431 + filename = filename.replace(/%22/g, '"');
  432 + filename = filename.replace(/&#([\d]{4});/g, function(m, code) {
  433 + return String.fromCharCode(code);
  434 + });
  435 + return filename;
  436 +};
  437 +
  438 +IncomingForm.prototype._initUrlencoded = function() {
  439 + this.type = 'urlencoded';
  440 +
  441 + var parser = new QuerystringParser(this.maxFields)
  442 + , self = this;
  443 +
  444 + parser.onField = function(key, val) {
  445 + self.emit('field', key, val);
  446 + };
  447 +
  448 + parser.onEnd = function() {
  449 + self.ended = true;
  450 + self._maybeEnd();
  451 + };
  452 +
  453 + this._parser = parser;
  454 +};
  455 +
  456 +IncomingForm.prototype._initOctetStream = function() {
  457 + this.type = 'octet-stream';
  458 + var filename = this.headers['x-file-name'];
  459 + var mime = this.headers['content-type'];
  460 +
  461 + var file = new File({
  462 + path: this._uploadPath(filename),
  463 + name: filename,
  464 + type: mime
  465 + });
  466 +
  467 + this.emit('fileBegin', filename, file);
  468 + file.open();
  469 +
  470 + this._flushing++;
  471 +
  472 + var self = this;
  473 +
  474 + self._parser = new OctetParser();
  475 +
  476 + //Keep track of writes that haven't finished so we don't emit the file before it's done being written
  477 + var outstandingWrites = 0;
  478 +
  479 + self._parser.on('data', function(buffer){
  480 + self.pause();
  481 + outstandingWrites++;
  482 +
  483 + file.write(buffer, function() {
  484 + outstandingWrites--;
  485 + self.resume();
  486 +
  487 + if(self.ended){
  488 + self._parser.emit('doneWritingFile');
  489 + }
  490 + });
  491 + });
  492 +
  493 + self._parser.on('end', function(){
  494 + self._flushing--;
  495 + self.ended = true;
  496 +
  497 + var done = function(){
  498 + file.end(function() {
  499 + self.emit('file', 'file', file);
  500 + self._maybeEnd();
  501 + });
  502 + };
  503 +
  504 + if(outstandingWrites === 0){
  505 + done();
  506 + } else {
  507 + self._parser.once('doneWritingFile', done);
  508 + }
  509 + });
  510 +};
  511 +
  512 +IncomingForm.prototype._initJSONencoded = function() {
  513 + this.type = 'json';
  514 +
  515 + var parser = new JSONParser(this)
  516 + , self = this;
  517 +
  518 + if (this.bytesExpected) {
  519 + parser.initWithLength(this.bytesExpected);
  520 + }
  521 +
  522 + parser.onField = function(key, val) {
  523 + self.emit('field', key, val);
  524 + };
  525 +
  526 + parser.onEnd = function() {
  527 + self.ended = true;
  528 + self._maybeEnd();
  529 + };
  530 +
  531 + this._parser = parser;
  532 +};
  533 +
  534 +IncomingForm.prototype._uploadPath = function(filename) {
  535 + var buf = crypto.randomBytes(16);
  536 + var name = 'upload_' + buf.toString('hex');
  537 +
  538 + if (this.keepExtensions) {
  539 + var ext = path.extname(filename);
  540 + ext = ext.replace(/(\.[a-z0-9]+).*/i, '$1');
  541 +
  542 + name += ext;
  543 + }
  544 +
  545 + return path.join(this.uploadDir, name);
  546 +};
  547 +
  548 +IncomingForm.prototype._maybeEnd = function() {
  549 + if (!this.ended || this._flushing || this.error) {
  550 + return;
  551 + }
  552 +
  553 + this.emit('end');
  554 +};
  555 +
  1 +var IncomingForm = require('./incoming_form').IncomingForm;
  2 +IncomingForm.IncomingForm = IncomingForm;
  3 +module.exports = IncomingForm;
  1 +if (global.GENTLY) require = GENTLY.hijack(require);
  2 +
  3 +var Buffer = require('buffer').Buffer;
  4 +
  5 +function JSONParser(parent) {
  6 + this.parent = parent;
  7 + this.data = new Buffer('');
  8 + this.bytesWritten = 0;
  9 +}
  10 +exports.JSONParser = JSONParser;
  11 +
  12 +JSONParser.prototype.initWithLength = function(length) {
  13 + this.data = new Buffer(length);
  14 +};
  15 +
  16 +JSONParser.prototype.write = function(buffer) {
  17 + if (this.data.length >= this.bytesWritten + buffer.length) {
  18 + buffer.copy(this.data, this.bytesWritten);
  19 + } else {
  20 + this.data = Buffer.concat([this.data, buffer]);
  21 + }
  22 + this.bytesWritten += buffer.length;
  23 + return buffer.length;
  24 +};
  25 +
  26 +JSONParser.prototype.end = function() {
  27 + try {
  28 + var fields = JSON.parse(this.data.toString('utf8'));
  29 + for (var field in fields) {
  30 + this.onField(field, fields[field]);
  31 + }
  32 + } catch (e) {
  33 + this.parent.emit('error', e);
  34 + }
  35 + this.data = null;
  36 +
  37 + this.onEnd();
  38 +};
  1 +var Buffer = require('buffer').Buffer,
  2 + s = 0,
  3 + S =
  4 + { PARSER_UNINITIALIZED: s++,
  5 + START: s++,
  6 + START_BOUNDARY: s++,
  7 + HEADER_FIELD_START: s++,
  8 + HEADER_FIELD: s++,
  9 + HEADER_VALUE_START: s++,
  10 + HEADER_VALUE: s++,
  11 + HEADER_VALUE_ALMOST_DONE: s++,
  12 + HEADERS_ALMOST_DONE: s++,
  13 + PART_DATA_START: s++,
  14 + PART_DATA: s++,
  15 + PART_END: s++,
  16 + END: s++
  17 + },
  18 +
  19 + f = 1,
  20 + F =
  21 + { PART_BOUNDARY: f,
  22 + LAST_BOUNDARY: f *= 2
  23 + },
  24 +
  25 + LF = 10,
  26 + CR = 13,
  27 + SPACE = 32,
  28 + HYPHEN = 45,
  29 + COLON = 58,
  30 + A = 97,
  31 + Z = 122,
  32 +
  33 + lower = function(c) {
  34 + return c | 0x20;
  35 + };
  36 +
  37 +for (s in S) {
  38 + exports[s] = S[s];
  39 +}
  40 +
  41 +function MultipartParser() {
  42 + this.boundary = null;
  43 + this.boundaryChars = null;
  44 + this.lookbehind = null;
  45 + this.state = S.PARSER_UNINITIALIZED;
  46 +
  47 + this.index = null;
  48 + this.flags = 0;
  49 +}
  50 +exports.MultipartParser = MultipartParser;
  51 +
  52 +MultipartParser.stateToString = function(stateNumber) {
  53 + for (var state in S) {
  54 + var number = S[state];
  55 + if (number === stateNumber) return state;
  56 + }
  57 +};
  58 +
  59 +MultipartParser.prototype.initWithBoundary = function(str) {
  60 + this.boundary = new Buffer(str.length+4);
  61 + this.boundary.write('\r\n--', 0);
  62 + this.boundary.write(str, 4);
  63 + this.lookbehind = new Buffer(this.boundary.length+8);
  64 + this.state = S.START;
  65 +
  66 + this.boundaryChars = {};
  67 + for (var i = 0; i < this.boundary.length; i++) {
  68 + this.boundaryChars[this.boundary[i]] = true;
  69 + }
  70 +};
  71 +
  72 +MultipartParser.prototype.write = function(buffer) {
  73 + var self = this,
  74 + i = 0,
  75 + len = buffer.length,
  76 + prevIndex = this.index,
  77 + index = this.index,
  78 + state = this.state,
  79 + flags = this.flags,
  80 + lookbehind = this.lookbehind,
  81 + boundary = this.boundary,
  82 + boundaryChars = this.boundaryChars,
  83 + boundaryLength = this.boundary.length,
  84 + boundaryEnd = boundaryLength - 1,
  85 + bufferLength = buffer.length,
  86 + c,
  87 + cl,
  88 +
  89 + mark = function(name) {
  90 + self[name+'Mark'] = i;
  91 + },
  92 + clear = function(name) {
  93 + delete self[name+'Mark'];
  94 + },
  95 + callback = function(name, buffer, start, end) {
  96 + if (start !== undefined && start === end) {
  97 + return;
  98 + }
  99 +
  100 + var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1);
  101 + if (callbackSymbol in self) {
  102 + self[callbackSymbol](buffer, start, end);
  103 + }
  104 + },
  105 + dataCallback = function(name, clear) {
  106 + var markSymbol = name+'Mark';
  107 + if (!(markSymbol in self)) {
  108 + return;
  109 + }
  110 +
  111 + if (!clear) {
  112 + callback(name, buffer, self[markSymbol], buffer.length);
  113 + self[markSymbol] = 0;
  114 + } else {
  115 + callback(name, buffer, self[markSymbol], i);
  116 + delete self[markSymbol];
  117 + }
  118 + };
  119 +
  120 + for (i = 0; i < len; i++) {
  121 + c = buffer[i];
  122 + switch (state) {
  123 + case S.PARSER_UNINITIALIZED:
  124 + return i;
  125 + case S.START:
  126 + index = 0;
  127 + state = S.START_BOUNDARY;
  128 + case S.START_BOUNDARY:
  129 + if (index == boundary.length - 2) {
  130 + if (c == HYPHEN) {
  131 + flags |= F.LAST_BOUNDARY;
  132 + } else if (c != CR) {
  133 + return i;
  134 + }
  135 + index++;
  136 + break;
  137 + } else if (index - 1 == boundary.length - 2) {
  138 + if (flags & F.LAST_BOUNDARY && c == HYPHEN){
  139 + callback('end');
  140 + state = S.END;
  141 + flags = 0;
  142 + } else if (!(flags & F.LAST_BOUNDARY) && c == LF) {
  143 + index = 0;
  144 + callback('partBegin');
  145 + state = S.HEADER_FIELD_START;
  146 + } else {
  147 + return i;
  148 + }
  149 + break;
  150 + }
  151 +
  152 + if (c != boundary[index+2]) {
  153 + index = -2;
  154 + }
  155 + if (c == boundary[index+2]) {
  156 + index++;
  157 + }
  158 + break;
  159 + case S.HEADER_FIELD_START:
  160 + state = S.HEADER_FIELD;
  161 + mark('headerField');
  162 + index = 0;
  163 + case S.HEADER_FIELD:
  164 + if (c == CR) {
  165 + clear('headerField');
  166 + state = S.HEADERS_ALMOST_DONE;
  167 + break;
  168 + }
  169 +
  170 + index++;
  171 + if (c == HYPHEN) {
  172 + break;
  173 + }
  174 +
  175 + if (c == COLON) {
  176 + if (index == 1) {
  177 + // empty header field
  178 + return i;
  179 + }
  180 + dataCallback('headerField', true);
  181 + state = S.HEADER_VALUE_START;
  182 + break;
  183 + }
  184 +
  185 + cl = lower(c);
  186 + if (cl < A || cl > Z) {
  187 + return i;
  188 + }
  189 + break;
  190 + case S.HEADER_VALUE_START:
  191 + if (c == SPACE) {
  192 + break;
  193 + }
  194 +
  195 + mark('headerValue');
  196 + state = S.HEADER_VALUE;
  197 + case S.HEADER_VALUE:
  198 + if (c == CR) {
  199 + dataCallback('headerValue', true);
  200 + callback('headerEnd');
  201 + state = S.HEADER_VALUE_ALMOST_DONE;
  202 + }
  203 + break;
  204 + case S.HEADER_VALUE_ALMOST_DONE:
  205 + if (c != LF) {
  206 + return i;
  207 + }
  208 + state = S.HEADER_FIELD_START;
  209 + break;
  210 + case S.HEADERS_ALMOST_DONE:
  211 + if (c != LF) {
  212 + return i;
  213 + }
  214 +
  215 + callback('headersEnd');
  216 + state = S.PART_DATA_START;
  217 + break;
  218 + case S.PART_DATA_START:
  219 + state = S.PART_DATA;
  220 + mark('partData');
  221 + case S.PART_DATA:
  222 + prevIndex = index;
  223 +
  224 + if (index === 0) {
  225 + // boyer-moore derrived algorithm to safely skip non-boundary data
  226 + i += boundaryEnd;
  227 + while (i < bufferLength && !(buffer[i] in boundaryChars)) {
  228 + i += boundaryLength;
  229 + }
  230 + i -= boundaryEnd;
  231 + c = buffer[i];
  232 + }
  233 +
  234 + if (index < boundary.length) {
  235 + if (boundary[index] == c) {
  236 + if (index === 0) {
  237 + dataCallback('partData', true);
  238 + }
  239 + index++;
  240 + } else {
  241 + index = 0;
  242 + }
  243 + } else if (index == boundary.length) {
  244 + index++;
  245 + if (c == CR) {
  246 + // CR = part boundary
  247 + flags |= F.PART_BOUNDARY;
  248 + } else if (c == HYPHEN) {
  249 + // HYPHEN = end boundary
  250 + flags |= F.LAST_BOUNDARY;
  251 + } else {
  252 + index = 0;
  253 + }
  254 + } else if (index - 1 == boundary.length) {
  255 + if (flags & F.PART_BOUNDARY) {
  256 + index = 0;
  257 + if (c == LF) {
  258 + // unset the PART_BOUNDARY flag
  259 + flags &= ~F.PART_BOUNDARY;
  260 + callback('partEnd');
  261 + callback('partBegin');
  262 + state = S.HEADER_FIELD_START;
  263 + break;
  264 + }
  265 + } else if (flags & F.LAST_BOUNDARY) {
  266 + if (c == HYPHEN) {
  267 + callback('partEnd');
  268 + callback('end');
  269 + state = S.END;
  270 + flags = 0;
  271 + } else {
  272 + index = 0;
  273 + }
  274 + } else {
  275 + index = 0;
  276 + }
  277 + }
  278 +
  279 + if (index > 0) {
  280 + // when matching a possible boundary, keep a lookbehind reference
  281 + // in case it turns out to be a false lead
  282 + lookbehind[index-1] = c;
  283 + } else if (prevIndex > 0) {
  284 + // if our boundary turned out to be rubbish, the captured lookbehind
  285 + // belongs to partData
  286 + callback('partData', lookbehind, 0, prevIndex);
  287 + prevIndex = 0;
  288 + mark('partData');
  289 +
  290 + // reconsider the current character even so it interrupted the sequence
  291 + // it could be the beginning of a new sequence
  292 + i--;
  293 + }
  294 +
  295 + break;
  296 + case S.END:
  297 + break;
  298 + default:
  299 + return i;
  300 + }
  301 + }
  302 +
  303 + dataCallback('headerField');
  304 + dataCallback('headerValue');
  305 + dataCallback('partData');
  306 +
  307 + this.index = index;
  308 + this.state = state;
  309 + this.flags = flags;
  310 +
  311 + return len;
  312 +};
  313 +
  314 +MultipartParser.prototype.end = function() {
  315 + var callback = function(self, name) {
  316 + var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1);
  317 + if (callbackSymbol in self) {
  318 + self[callbackSymbol]();
  319 + }
  320 + };
  321 + if ((this.state == S.HEADER_FIELD_START && this.index === 0) ||
  322 + (this.state == S.PART_DATA && this.index == this.boundary.length)) {
  323 + callback(this, 'partEnd');
  324 + callback(this, 'end');
  325 + } else if (this.state != S.END) {
  326 + return new Error('MultipartParser.end(): stream ended unexpectedly: ' + this.explain());
  327 + }
  328 +};
  329 +
  330 +MultipartParser.prototype.explain = function() {
  331 + return 'state = ' + MultipartParser.stateToString(this.state);
  332 +};
  1 +var EventEmitter = require('events').EventEmitter
  2 + , util = require('util');
  3 +
  4 +function OctetParser(options){
  5 + if(!(this instanceof OctetParser)) return new OctetParser(options);
  6 + EventEmitter.call(this);
  7 +}
  8 +
  9 +util.inherits(OctetParser, EventEmitter);
  10 +
  11 +exports.OctetParser = OctetParser;
  12 +
  13 +OctetParser.prototype.write = function(buffer) {
  14 + this.emit('data', buffer);
  15 + return buffer.length;
  16 +};
  17 +
  18 +OctetParser.prototype.end = function() {
  19 + this.emit('end');
  20 +};
  1 +if (global.GENTLY) require = GENTLY.hijack(require);
  2 +
  3 +// This is a buffering parser, not quite as nice as the multipart one.
  4 +// If I find time I'll rewrite this to be fully streaming as well
  5 +var querystring = require('querystring');
  6 +
  7 +function QuerystringParser(maxKeys) {
  8 + this.maxKeys = maxKeys;
  9 + this.buffer = '';
  10 +}
  11 +exports.QuerystringParser = QuerystringParser;
  12 +
  13 +QuerystringParser.prototype.write = function(buffer) {
  14 + this.buffer += buffer.toString('ascii');
  15 + return buffer.length;
  16 +};
  17 +
  18 +QuerystringParser.prototype.end = function() {
  19 + var fields = querystring.parse(this.buffer, '&', '=', { maxKeys: this.maxKeys });
  20 + for (var field in fields) {
  21 + this.onField(field, fields[field]);
  22 + }
  23 + this.buffer = '';
  24 +
  25 + this.onEnd();
  26 +};
  27 +
  1 +{
  2 + "_args": [
  3 + [
  4 + {
  5 + "raw": "formidable@1.1.1",
  6 + "scope": null,
  7 + "escapedName": "formidable",
  8 + "name": "formidable",
  9 + "rawSpec": "1.1.1",
  10 + "spec": "1.1.1",
  11 + "type": "version"
  12 + },
  13 + "/Users/fzy/project/koa2_Sequelize_project/node_modules/koa-body"
  14 + ]
  15 + ],
  16 + "_from": "formidable@1.1.1",
  17 + "_id": "formidable@1.1.1",
  18 + "_inCache": true,
  19 + "_location": "/formidable",
  20 + "_nodeVersion": "7.2.1",
  21 + "_npmOperationalInternal": {
  22 + "host": "packages-12-west.internal.npmjs.com",
  23 + "tmp": "tmp/formidable-1.1.1.tgz_1484514649272_0.35996662196703255"
  24 + },
  25 + "_npmUser": {
  26 + "name": "kornel",
  27 + "email": "pornel@pornel.net"
  28 + },
  29 + "_npmVersion": "4.0.5",
  30 + "_phantomChildren": {},
  31 + "_requested": {
  32 + "raw": "formidable@1.1.1",
  33 + "scope": null,
  34 + "escapedName": "formidable",
  35 + "name": "formidable",
  36 + "rawSpec": "1.1.1",
  37 + "spec": "1.1.1",
  38 + "type": "version"
  39 + },
  40 + "_requiredBy": [
  41 + "/koa-body"
  42 + ],
  43 + "_resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz",
  44 + "_shasum": "96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9",
  45 + "_shrinkwrap": null,
  46 + "_spec": "formidable@1.1.1",
  47 + "_where": "/Users/fzy/project/koa2_Sequelize_project/node_modules/koa-body",
  48 + "bugs": {
  49 + "url": "http://github.com/felixge/node-formidable/issues"
  50 + },
  51 + "dependencies": {},
  52 + "description": "A node.js module for parsing form data, especially file uploads.",
  53 + "devDependencies": {
  54 + "findit": "^0.1.2",
  55 + "gently": "^0.8.0",
  56 + "hashish": "^0.0.4",
  57 + "request": "^2.11.4",
  58 + "urun": "^0.0.6",
  59 + "utest": "^0.0.8"
  60 + },
  61 + "directories": {
  62 + "lib": "./lib"
  63 + },
  64 + "dist": {
  65 + "shasum": "96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9",
  66 + "tarball": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz"
  67 + },
  68 + "engines": {
  69 + "node": ">=0.8.0"
  70 + },
  71 + "gitHead": "7a36a8e932044252fe648c81dbd8cf837d0178d0",
  72 + "homepage": "https://github.com/felixge/node-formidable",
  73 + "license": "MIT",
  74 + "main": "./lib/index",
  75 + "maintainers": [
  76 + {
  77 + "name": "felixge",
  78 + "email": "felix@debuggable.com"
  79 + },
  80 + {
  81 + "name": "kornel",
  82 + "email": "pornel@pornel.net"
  83 + },
  84 + {
  85 + "name": "superjoe",
  86 + "email": "superjoe30@gmail.com"
  87 + },
  88 + {
  89 + "name": "svnlto",
  90 + "email": "me@svenlito.com"
  91 + },
  92 + {
  93 + "name": "tim-smart",
  94 + "email": "tim@fostle.com"
  95 + },
  96 + {
  97 + "name": "tunnckocore",
  98 + "email": "mameto_100@mail.bg"
  99 + }
  100 + ],
  101 + "name": "formidable",
  102 + "optionalDependencies": {},
  103 + "readme": "# Formidable\n\n[![Build Status](https://travis-ci.org/felixge/node-formidable.svg?branch=master)](https://travis-ci.org/felixge/node-formidable)\n\n## Purpose\n\nA Node.js module for parsing form data, especially file uploads.\n\n## Current status\n\n**Maintainers Wanted:** Please see https://github.com/felixge/node-formidable/issues/412\n\nThis module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading\nand encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from\na large variety of clients and is considered production-ready.\n\n## Features\n\n* Fast (~500mb/sec), non-buffering multipart parser\n* Automatically writing file uploads to disk\n* Low memory footprint\n* Graceful error handling\n* Very high test coverage\n\n## Installation\n\n```sh\nnpm i -S formidable\n```\n\nThis is a low level package, and if you're using a high level framework such as Express, chances are it's already included in it. You can [read this discussion](http://stackoverflow.com/questions/11295554/how-to-disable-express-bodyparser-for-file-uploads-node-js) about how Formidable is integrated with Express.\n\nNote: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library.\n\n## Example\n\nParse an incoming file upload.\n```javascript\nvar formidable = require('formidable'),\n http = require('http'),\n util = require('util');\n\nhttp.createServer(function(req, res) {\n if (req.url == '/upload' && req.method.toLowerCase() == 'post') {\n // parse a file upload\n var form = new formidable.IncomingForm();\n\n form.parse(req, function(err, fields, files) {\n res.writeHead(200, {'content-type': 'text/plain'});\n res.write('received upload:\\n\\n');\n res.end(util.inspect({fields: fields, files: files}));\n });\n\n return;\n }\n\n // show a file upload form\n res.writeHead(200, {'content-type': 'text/html'});\n res.end(\n '<form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">'+\n '<input type=\"text\" name=\"title\"><br>'+\n '<input type=\"file\" name=\"upload\" multiple=\"multiple\"><br>'+\n '<input type=\"submit\" value=\"Upload\">'+\n '</form>'\n );\n}).listen(8080);\n```\n## API\n\n### Formidable.IncomingForm\n```javascript\nvar form = new formidable.IncomingForm()\n```\nCreates a new incoming form.\n\n```javascript\nform.encoding = 'utf-8';\n```\nSets encoding for incoming form fields.\n\n```javascript\nform.uploadDir = \"/my/dir\";\n```\nSets the directory for placing file uploads in. You can move them later on using\n`fs.rename()`. The default is `os.tmpdir()`.\n\n```javascript\nform.keepExtensions = false;\n```\nIf you want the files written to `form.uploadDir` to include the extensions of the original files, set this property to `true`.\n\n```javascript\nform.type\n```\nEither 'multipart' or 'urlencoded' depending on the incoming request.\n\n```javascript\nform.maxFieldsSize = 2 * 1024 * 1024;\n```\nLimits the amount of memory all fields together (except files) can allocate in bytes.\nIf this value is exceeded, an `'error'` event is emitted. The default\nsize is 2MB.\n\n```javascript\nform.maxFields = 1000;\n```\nLimits the number of fields that the querystring parser will decode. Defaults\nto 1000 (0 for unlimited).\n\n```javascript\nform.hash = false;\n```\nIf you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`.\n\n```javascript\nform.multiples = false;\n```\nIf this option is enabled, when you call `form.parse`, the `files` argument will contain arrays of files for inputs which submit multiple files using the HTML5 `multiple` attribute.\n\n```javascript\nform.bytesReceived\n```\nThe amount of bytes received for this form so far.\n\n```javascript\nform.bytesExpected\n```\nThe expected number of bytes in this form.\n\n```javascript\nform.parse(request, [cb]);\n```\nParses an incoming node.js `request` containing form data. If `cb` is provided, all fields and files are collected and passed to the callback:\n\n\n```javascript\nform.parse(req, function(err, fields, files) {\n // ...\n});\n\nform.onPart(part);\n```\nYou may overwrite this method if you are interested in directly accessing the multipart stream. Doing so will disable any `'field'` / `'file'` events processing which would occur otherwise, making you fully responsible for handling the processing.\n\n```javascript\nform.onPart = function(part) {\n part.addListener('data', function() {\n // ...\n });\n}\n```\nIf you want to use formidable to only handle certain parts for you, you can do so:\n```javascript\nform.onPart = function(part) {\n if (!part.filename) {\n // let formidable handle all non-file parts\n form.handlePart(part);\n }\n}\n```\nCheck the code in this method for further inspiration.\n\n\n### Formidable.File\n```javascript\nfile.size = 0\n```\nThe size of the uploaded file in bytes. If the file is still being uploaded (see `'fileBegin'` event), this property says how many bytes of the file have been written to disk yet.\n```javascript\nfile.path = null\n```\nThe path this file is being written to. You can modify this in the `'fileBegin'` event in\ncase you are unhappy with the way formidable generates a temporary path for your files.\n```javascript\nfile.name = null\n```\nThe name this file had according to the uploading client.\n```javascript\nfile.type = null\n```\nThe mime type of this file, according to the uploading client.\n```javascript\nfile.lastModifiedDate = null\n```\nA date object (or `null`) containing the time this file was last written to. Mostly\nhere for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).\n```javascript\nfile.hash = null\n```\nIf hash calculation was set, you can read the hex digest out of this var.\n\n#### Formidable.File#toJSON()\n\n This method returns a JSON-representation of the file, allowing you to\n `JSON.stringify()` the file which is useful for logging and responding\n to requests.\n\n### Events\n\n\n#### 'progress'\n\nEmitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.\n\n```javascript\nform.on('progress', function(bytesReceived, bytesExpected) {\n});\n```\n\n\n\n#### 'field'\n\nEmitted whenever a field / value pair has been received.\n\n```javascript\nform.on('field', function(name, value) {\n});\n```\n\n#### 'fileBegin'\n\nEmitted whenever a new file is detected in the upload stream. Use this event if\nyou want to stream the file to somewhere else while buffering the upload on\nthe file system.\n\n```javascript\nform.on('fileBegin', function(name, file) {\n});\n```\n\n#### 'file'\n\nEmitted whenever a field / file pair has been received. `file` is an instance of `File`.\n\n```javascript\nform.on('file', function(name, file) {\n});\n```\n\n#### 'error'\n\nEmitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call `request.resume()` if you want the request to continue firing `'data'` events.\n\n```javascript\nform.on('error', function(err) {\n});\n```\n\n#### 'aborted'\n\n\nEmitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. After this event is emitted, an `error` event will follow. In the future there will be a separate 'timeout' event (needs a change in the node core).\n```javascript\nform.on('aborted', function() {\n});\n```\n\n##### 'end'\n```javascript\nform.on('end', function() {\n});\n```\nEmitted when the entire request has been received, and all contained files have finished flushing to disk. This is a great place for you to send your response.\n\n\n\n## Changelog\n\n### v1.1.1 (2017-01-15)\n\n * Fix DeprecationWarning about os.tmpDir() (Christian)\n * Update `buffer.write` order of arguments for Node 7 (Kornel Lesiński)\n * JSON Parser emits error events to the IncomingForm (alessio.montagnani)\n * Improved Content-Disposition parsing (Sebastien)\n * Access WriteStream of fs during runtime instead of include time (Jonas Amundsen)\n * Use built-in toString to convert buffer to hex (Charmander)\n * Add hash to json if present (Nick Stamas)\n * Add license to package.json (Simen Bekkhus)\n\n### v1.0.14 (2013-05-03)\n\n* Add failing hash tests. (Ben Trask)\n* Enable hash calculation again (Eugene Girshov)\n* Test for immediate data events (Tim Smart)\n* Re-arrange IncomingForm#parse (Tim Smart)\n\n### v1.0.13\n\n* Only update hash if update method exists (Sven Lito)\n* According to travis v0.10 needs to go quoted (Sven Lito)\n* Bumping build node versions (Sven Lito)\n* Additional fix for empty requests (Eugene Girshov)\n* Change the default to 1000, to match the new Node behaviour. (OrangeDog)\n* Add ability to control maxKeys in the querystring parser. (OrangeDog)\n* Adjust test case to work with node 0.9.x (Eugene Girshov)\n* Update package.json (Sven Lito)\n* Path adjustment according to eb4468b (Markus Ast)\n\n### v1.0.12\n\n* Emit error on aborted connections (Eugene Girshov)\n* Add support for empty requests (Eugene Girshov)\n* Fix name/filename handling in Content-Disposition (jesperp)\n* Tolerate malformed closing boundary in multipart (Eugene Girshov)\n* Ignore preamble in multipart messages (Eugene Girshov)\n* Add support for application/json (Mike Frey, Carlos Rodriguez)\n* Add support for Base64 encoding (Elmer Bulthuis)\n* Add File#toJSON (TJ Holowaychuk)\n* Remove support for Node.js 0.4 & 0.6 (Andrew Kelley)\n* Documentation improvements (Sven Lito, Andre Azevedo)\n* Add support for application/octet-stream (Ion Lupascu, Chris Scribner)\n* Use os.tmpdir() to get tmp directory (Andrew Kelley)\n* Improve package.json (Andrew Kelley, Sven Lito)\n* Fix benchmark script (Andrew Kelley)\n* Fix scope issue in incoming_forms (Sven Lito)\n* Fix file handle leak on error (OrangeDog)\n\n## License\n\nFormidable is licensed under the MIT license.\n\n## Ports\n\n* [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++ parser based on formidable\n\n## Credits\n\n* [Ryan Dahl](http://twitter.com/ryah) for his work on [http-parser](http://github.com/ry/http-parser) which heavily inspired multipart_parser.js\n",
  104 + "readmeFilename": "Readme.md",
  105 + "repository": {
  106 + "type": "git",
  107 + "url": "git://github.com/felixge/node-formidable.git"
  108 + },
  109 + "scripts": {
  110 + "clean": "rm test/tmp/*",
  111 + "test": "node test/run.js"
  112 + },
  113 + "version": "1.1.1"
  114 +}
  1 +# Security holding package
  2 +
  3 +This package name is not currently in use, but was formerly occupied
  4 +by another package. To avoid malicious use, npm is hanging on to the
  5 +package name, but loosely, and we'll probably give it to you if you
  6 +want it.
  7 +
  8 +You may adopt this package by contacting support@npmjs.com and
  9 +requesting the name.
  1 +{
  2 + "_args": [
  3 + [
  4 + {
  5 + "raw": "fs",
  6 + "scope": null,
  7 + "escapedName": "fs",
  8 + "name": "fs",
  9 + "rawSpec": "",
  10 + "spec": "latest",
  11 + "type": "tag"
  12 + },
  13 + "/Users/fzy/project/koa2_Sequelize_project/util/Agora_Recording_SDK_for_Linux_FULL/samples"
  14 + ]
  15 + ],
  16 + "_from": "fs@latest",
  17 + "_id": "fs@0.0.1-security",
  18 + "_inCache": true,
  19 + "_location": "/fs",
  20 + "_nodeVersion": "4.1.2",
  21 + "_npmUser": {
  22 + "name": "ehsalazar",
  23 + "email": "ernie@npmjs.com"
  24 + },
  25 + "_npmVersion": "3.10.5",
  26 + "_phantomChildren": {},
  27 + "_requested": {
  28 + "raw": "fs",
  29 + "scope": null,
  30 + "escapedName": "fs",
  31 + "name": "fs",
  32 + "rawSpec": "",
  33 + "spec": "latest",
  34 + "type": "tag"
  35 + },
  36 + "_requiredBy": [
  37 + "#DEV:/",
  38 + "#USER"
  39 + ],
  40 + "_resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
  41 + "_shasum": "8a7bd37186b6dddf3813f23858b57ecaaf5e41d4",
  42 + "_shrinkwrap": null,
  43 + "_spec": "fs",
  44 + "_where": "/Users/fzy/project/koa2_Sequelize_project/util/Agora_Recording_SDK_for_Linux_FULL/samples",
  45 + "author": "",
  46 + "bugs": {
  47 + "url": "https://github.com/npm/security-holder/issues"
  48 + },
  49 + "dependencies": {},
  50 + "description": "This package name is not currently in use, but was formerly occupied by another package. To avoid malicious use, npm is hanging on to the package name, but loosely, and we'll probably give it to you if you want it.",
  51 + "devDependencies": {},
  52 + "directories": {},
  53 + "dist": {
  54 + "shasum": "8a7bd37186b6dddf3813f23858b57ecaaf5e41d4",
  55 + "tarball": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz"
  56 + },
  57 + "homepage": "https://github.com/npm/security-holder#readme",
  58 + "keywords": [],
  59 + "license": "ISC",
  60 + "main": "index.js",
  61 + "maintainers": [
  62 + {
  63 + "name": "ehsalazar",
  64 + "email": "ernie@npmjs.com"
  65 + }
  66 + ],
  67 + "name": "fs",
  68 + "optionalDependencies": {},
  69 + "readme": "# Security holding package\n\nThis package name is not currently in use, but was formerly occupied\nby another package. To avoid malicious use, npm is hanging on to the\npackage name, but loosely, and we'll probably give it to you if you\nwant it.\n\nYou may adopt this package by contacting support@npmjs.com and\nrequesting the name.\n",
  70 + "readmeFilename": "README.md",
  71 + "repository": {
  72 + "type": "git",
  73 + "url": "git+https://github.com/npm/security-holder.git"
  74 + },
  75 + "scripts": {
  76 + "test": "echo \"Error: no test specified\" && exit 1"
  77 + },
  78 + "version": "0.0.1-security"
  79 +}
  1 +test/
  2 +examples/
  1 +before_install:
  2 + - sudo apt-get update
  3 + - sudo apt-get install imagemagick graphicsmagick
  4 +language: node_js
  5 +node_js:
  6 + - "6"
  7 + - "4"
  8 + - "0.10"
  9 + - "0.12"
  10 + - "iojs-v2"
  1 +fatal: Invalid refspec '/dev/null'
  1 +
  2 +1.23.0 / 2016-08-03
  3 +
  4 + * fixed; webpack support #547 sean-shirazi
  5 + * fixed; windows support - use cross-spawn to spawn processes #537 bdukes
  6 + * added; allow thumbnail to accept the same options as resize #527 Sebmaster
  7 + * added; dispose support #487 dlwr
  8 + * docs; add example of loading image from URL #544 wahengchang
  9 + * docs; Fix a link in README.md #532 clbn
  10 + * travis; update travis versions #551 amilajack
  11 +
  12 +1.22.0 / 2016-04-07
  13 +
  14 + * fixed; identity parser: support multi-value keys by creating an array #508 #509 [emaniacs](https://github.com/emaniacs)
  15 + * fixed; error handling if gm is not installed #499 [aeo3](https://github.com/aeo3)
  16 + * fixed; highlightColor typo in compare #504 [DanielHudson](https://github.com/DanielHudson)
  17 + * docs; Fix typo #475 [rodrigoalviani](https://github.com/rodrigoalviani)
  18 +
  19 +1.21.1 / 2015-10-26
  20 +
  21 +* fixed: Fixed #465 hard coded gm binary, also fixed issues with compare and fixed tests so they will fail on subsequent runs when they should do [rwky](https://github.com/rwky)
  22 +
  23 +1.21.0 / 2015-10-26 **contains security fix**
  24 +
  25 +* fixed: gm.compare fails to escape arguments properly (Reported by Brendan Scarvell) [rwky](https://github.com/rwky)
  26 +
  27 +1.20.0 / 2015-09-23
  28 +
  29 +* changed: Reverted "Add format inference from filename for buffers/streams" due to errors #448
  30 +
  31 +1.19.0 / 2015-09-16
  32 +
  33 +* changed: Added error to notify about image magick not supporting minify [encima](https://github.com/encima)
  34 +* changed: Refactored orientation getter to use faster identify call [lbeschastny](https://github.com/lbeschastny)
  35 +* added: resizeExact function [DanMMX](https://github.com/DanMMX)
  36 +* added: thumbExact function [DanMMX](https://github.com/DanMMX)
  37 +* added: Add format inference from filename for buffers/streams [adurrive](https://github.com/adurrive)
  38 +* fixed: Hex values when passed to compare aren't quoted automatically [DanMMX](https://github.com/DanMMX)
  39 +* fixed: identify returning last frame size instead of the larges on animated gifs [preynal](https://github.com/preynal)
  40 +* docs: Updated docs [laurilehmijoki](https://github.com/laurilehmijoki)
  41 +
  42 +1.18.1 / 2015-05-18
  43 +
  44 +* changed: Added io.js support [rwky](https://github.com/rwky)
  45 +
  46 +1.18.0 / 2015-05-18
  47 +
  48 +* changed: Removed support for node 0.8 and added support for 0.12 [rwky](https://github.com/rwky)
  49 +* changed: Listen to stdin error event for spawn errors [kapouer](https://github.com/kapouer)
  50 +* changed: Improved error handling when gm isn't installed [FreshXOpenSource](https://github.com/FreshXOpenSource)
  51 +* changed: Allow append method to use an array of arguments [emohacker](https://github.com/emohacker)
  52 +* changed: appPath option now specifies full path to gm binary John Borkowski
  53 +* changed: Ignore warning messages for identify [asrail](https://github.com/asrail)
  54 +* added: Montage method [donaldpcook](https://github.com/donaldpcook)
  55 +* added: Progressive option to thumb [mohebifar](https://github.com/mohebifar)
  56 +* added: Native gm auto-orient for use with gm >= 1.3.18 [bog](https://github.com/bog)
  57 +* added: Timeout support by passing the timeout option in milliseconds [marcbachmann](https://github.com/marcbachmann)
  58 +* fixed: density when using ImageMagick [syzer](https://github.com/syzer)
  59 +* fixed: resize behaviour for falsy values [adius](https://github.com/adius)
  60 +
  61 +
  62 +1.17.0 / 2014-10-28
  63 +==================
  64 +
  65 + * changed: extended compare callback also returns the file names #297 [mastix](https://github.com/mastix)
  66 + * changed: pass spawn crash to callback #306 [medikoo](https://github.com/medikoo)
  67 + * changed: geometry supports arbitary string as first argument #330 [jdiez17](https://github.com/jdiez17)
  68 + * added: support for repage+ option #275 [desigens](https://github.com/desigens)
  69 + * added: added the dissolve command #300 [microadm](https://github.com/microadam)
  70 + * added: composite method #332 [jdiez17](https://github.com/jdiez17)
  71 + * fixed: cannot set tolerance to 0 #302 [rwky](https://github.com/rwky)
  72 + * fixed: handle empty buffers #330 [alcidesv](https://github.com/alcidesv)
  73 +
  74 +1.16.0 / 2014-05-09
  75 +==================
  76 +
  77 + * fixed; dropped "+" when 0 passed as vertical roll amt #267 [dwtkns](https://github.com/dwtkns)
  78 + * added; highlight-style support #272 [fdecampredon](https://github.com/fdecampredon)
  79 +
  80 +1.15.0 / 2014-05-03
  81 +===================
  82 +
  83 + * changed; gm.compare logic to always run the mse comparison as expected #258 [Vokkim](https://github.com/Vokkim)
  84 + * added; `tolerance` to gm.compare options object #258 [Vokkim](https://github.com/Vokkim)
  85 + * added; option to set ImageMagick application path explicitly #250 (akreitals)
  86 + * fixed; gm.compare: support values like 9.51582e-05 #260 [normanrz](https://github.com/normanrz)
  87 + * README: add call for maintainers
  88 +
  89 +1.14.2 / 2013-12-24
  90 +===================
  91 +
  92 +* fixed; background is now a setting #246 (PEM--)
  93 +
  94 +1.14.1 / 2013-12-09
  95 +===================
  96 +
  97 +* fixed; identify -verbose colon behavior #240 ludow
  98 +
  99 +1.14.0 / 2013-12-04
  100 +===================
  101 +
  102 +* added; compare method for imagemagick (longlho)
  103 +
  104 +1.13.3 / 2013-10-22
  105 +===================
  106 +
  107 +* fixed; escape diffOptions.file in compare (dwabyick)
  108 +
  109 +1.13.2 / 2013-10-18
  110 +===================
  111 +
  112 +* fixed; density is a setting not an operator
  113 +
  114 +1.13.1 / 2013-09-15
  115 +===================
  116 +
  117 +* added; boolean for % crop
  118 +
  119 +1.13.0 / 2013-09-07
  120 +===================
  121 +
  122 +* added; morph more than two images (overra)
  123 +
  124 +1.12.2 / 2013-08-29
  125 +===================
  126 +
  127 +* fixed; fallback to through in node 0.8
  128 +
  129 +1.12.1 / 2013-08-29 (unpublished)
  130 +===================
  131 +
  132 +* refactor; replace through with stream.PassThrough
  133 +
  134 +1.12.0 / 2013-08-27
  135 +===================
  136 +
  137 +* added; diff image output file (chenglou)
  138 +
  139 +1.11.1 / 2013-08-17
  140 +===================
  141 +
  142 +* added; proto.selectFrame(#)
  143 +* fixed; getters should not ignore frame selection
  144 +
  145 +1.11.0 / 2013-07-23
  146 +===================
  147 +
  148 +* added; optional formatting string for gm().identify(format, callback) (tornillo)
  149 +* removed; error messages when gm/im binary is not installed
  150 +
  151 +1.10.0 / 2013-06-27
  152 +===================
  153 +
  154 +* refactor; use native `-auto-orient` for imagemagick
  155 +
  156 +1.9.2 / 2013-06-12
  157 +==================
  158 +
  159 + * refactor; move `streamToBuffer` to a separate module
  160 + * fixed; .stream(format) without a callback
  161 +
  162 +1.9.1 / 2013-05-07
  163 +==================
  164 +
  165 + * fixed; gm().resize(width) always only resizes width
  166 + * fixed; gm('img.gif').format() returns the format of the first frame
  167 +
  168 +1.9.0 / 2013-04-21
  169 +==================
  170 +
  171 + * added; node v0.10 support
  172 + * removed; node < v0.8 support - `Buffer.concat()`
  173 + * tests; all tests now run on Travis
  174 + * added; gm().stream() returns a stream when no callback is present
  175 + * added; gm().toBuffer(callback)
  176 + * fixed; gm().size() only returns the size of the first frame of a GIF
  177 +
  178 +1.8.2 / 2013-03-07
  179 +==================
  180 +
  181 + * include source path in identify data #126 [soupdiver](https://github.com/soupdiver)
  182 +
  183 +1.8.1 / 2012-12-21
  184 +==================
  185 +
  186 + * Avoid losing already set arguments on identify #105 #113 #109 [JNissi](https://github.com/JNissi)
  187 + * tests; add autoOrient + thumb() test
  188 + * tests; add test case for #113
  189 + * tests; added test for #109
  190 + * tests; add resize on buffer test
  191 +
  192 +1.8.0 / 2012-12-14
  193 +==================
  194 +
  195 + * added; geometry support to scale() #98
  196 + * removed; incorrect/broken dissolve() method (never worked)
  197 + * fixed; handle child_proc error when using Buffer input #109
  198 + * fixed; use of Buffers with identify() #109
  199 + * fixed; no longer include -size arg with resize() #98
  200 + * fixed; remove -size arg from extent() #103
  201 + * fixed; magnify support
  202 + * fixed; autoOrient to work with all types of exif orientations [dambalah](https://github.com/dambalah) #108
  203 + * tests; npm test runs unit only (now compatible with travis)
  204 + * tests; fix magnify test on imagemagick
  205 + * tests; added for cmd line args
  206 +
  207 +1.7.0 / 2012-12-06
  208 +==================
  209 +
  210 + * added; gm.compare support
  211 + * added; passing Buffers directly [danmilon](https://github.com/danmilon)
  212 +
  213 +1.6.1 / 2012-11-13
  214 +==================
  215 +
  216 + * fixed regression; only pass additional params on error #96
  217 +
  218 +1.6.0 / 2012-11-10
  219 +==================
  220 +
  221 + * changed; rename internal buffer to _buffer #88 [kof](https://github.com/kof)
  222 + * changed; optimized identify getters (format, depth, size, color, filesize). #83 please read this for details: https://github.com/aheckmann/gm/commit/8fcf3f8f84a02cc2001da874cbebb89bf7084409
  223 + * added; visionmedia/debug support
  224 + * added; `gm convert -thumbnail` support. _differs from thumb()._ [danmilon](https://github.com/danmilon)
  225 + * fixed; -rotate 0 support #90
  226 + * fixed; multi-execution of same gm instance arguments corruption
  227 + * fixed; gracefully handle parser errors #94 [eldilibra](https://github.com/eldilibra)
  228 +
  229 +1.5.1 / 2012-10-02
  230 +==================
  231 +
  232 + * fixed; passing multiple paths to append() #77
  233 +
  234 +1.5.0 / 2012-09-15
  235 +==================
  236 +
  237 + * fixed; callback scope
  238 + * fixed; append() usage #77
  239 +
  240 +1.4.2 / 2012-08-17
  241 +==================
  242 +
  243 + * fixed; identify parsing for ImageMagick exif data (#58)
  244 + * fixed; when in imageMagick mode, complain about missing imageMagick [bcherry](https://github.com/bcherry) (#73)
  245 + * added; tests
  246 +
  247 +1.4.1 / 2012-07-31
  248 +==================
  249 +
  250 + * fixed; scenes() args
  251 + * fixed; accept the left-to-right arg of append()
  252 + * added; _subCommand
  253 +
  254 +## v1.4 - 07/28/2012
  255 +
  256 + * added; adjoin() [Math-]
  257 + * added; affine() [Math-]
  258 + * added; append() [Math-]
  259 + * added; authenticate() [Math-]
  260 + * added; average() [Math-]
  261 + * added; backdrop() [Math-]
  262 + * added; blackThreshold() [Math-]
  263 + * added; bluePrimary() [Math-]
  264 + * added; border() [Math-]
  265 + * added; borderColor() [Math-]
  266 + * added; box() [Math-]
  267 + * added; channel() [Math-]
  268 + * added; clip() [Math-]
  269 + * added; coalesce() [Math-]
  270 + * added; colorMap() [Math-]
  271 + * added; compose() [Math-]
  272 + * added; compress() [Math-]
  273 + * added; convolve() [Math-]
  274 + * added; createDirectories() [Math-]
  275 + * added; deconstruct() [Math-]
  276 + * added; delay() [Math-]
  277 + * added; define() [Math-]
  278 + * added; displace() [Math-]
  279 + * added; display() [Math-]
  280 + * added; dispose() [Math-]
  281 + * added; disolve() [Math-]
  282 + * added; encoding() [Math-]
  283 + * added; endian() [Math-]
  284 + * added; file() [Math-]
  285 + * added; flatten() [Math-]
  286 + * added; foreground() [Math-]
  287 + * added; frame() [Math-]
  288 + * added; fuzz() [Math-]
  289 + * added; gaussian() [Math-]
  290 + * added; geometry() [Math-]
  291 + * added; greenPrimary() [Math-]
  292 + * added; highlightColor() [Math-]
  293 + * added; highlightStyle() [Math-]
  294 + * added; iconGeometry() [Math-]
  295 + * added; intent() [Math-]
  296 + * added; lat() [Math-]
  297 + * added; level() [Math-]
  298 + * added; list() [Math-]
  299 + * added; log() [Math-]
  300 + * added; map() [Math-]
  301 + * added; matte() [Math-]
  302 + * added; matteColor() [Math-]
  303 + * added; mask() [Math-]
  304 + * added; maximumError() [Math-]
  305 + * added; mode() [Math-]
  306 + * added; monitor() [Math-]
  307 + * added; mosaic() [Math-]
  308 + * added; motionBlur() [Math-]
  309 + * added; name() [Math-]
  310 + * added; noop() [Math-]
  311 + * added; normalize() [Math-]
  312 + * added; opaque() [Math-]
  313 + * added; operator() [Math-]
  314 + * added; orderedDither() [Math-]
  315 + * added; outputDirectory() [Math-]
  316 + * added; page() [Math-]
  317 + * added; pause() [Math-]
  318 + * added; pen() [Math-]
  319 + * added; ping() [Math-]
  320 + * added; pointSize() [Math-]
  321 + * added; preview() [Math-]
  322 + * added; process() [Math-]
  323 + * added; profile() [Math-]
  324 + * added; progress() [Math-]
  325 + * added; rawSize() [Math-]
  326 + * added; randomThreshold() [Math-]
  327 + * added; recolor() [Math-]
  328 + * added; redPrimary() [Math-]
  329 + * added; remote() [Math-]
  330 + * added; render() [Math-]
  331 + * added; repage() [Math-]
  332 + * added; sample() [Math-]
  333 + * added; samplingFactor() [Math-]
  334 + * added; scene() [Math-]
  335 + * added; scenes() [Math-]
  336 + * added; screen() [Math-]
  337 + * added; segment() [Math-]
  338 + * added; set() [Math-]
  339 + * added; shade() [Math-]
  340 + * added; shadow() [Math-]
  341 + * added; sharedMemory() [Math-]
  342 + * added; shave() [Math-]
  343 + * added; shear() [Math-]
  344 + * added; silent() [Math-]
  345 + * added; snaps() [Math-]
  346 + * added; stagano() [Math-]
  347 + * added; stereo() [Math-]
  348 + * added; textFont() [Math-]
  349 + * added; texture() [Math-]
  350 + * added; threshold() [Math-]
  351 + * added; tile() [Math-]
  352 + * added; transform() [Math-]
  353 + * added; transparent() [Math-]
  354 + * added; treeDepth() [Math-]
  355 + * added; update() [Math-]
  356 + * added; units() [Math-]
  357 + * added; unsharp() [Math-]
  358 + * added; usePixmap() [Math-]
  359 + * added; view() [Math-]
  360 + * added; virtualPixel() [Math-]
  361 + * added; visual() [Math-]
  362 + * added; watermark() [Math-]
  363 + * added; wave() [Math-]
  364 + * added; whitePoint() [Math-]
  365 + * added; whiteThreshold() [Math-]
  366 + * added; window() [Math-]
  367 + * added; windowGroup() [Math-]
  368 +
  369 +## v1.3.2 - 06/22/2012
  370 +
  371 + * added; node >= 0.7/0.8 compat
  372 +
  373 +## v1.3.1 - 06/06/2012
  374 +
  375 + * fixed; thumb() alignment and cropping [thomaschaaf]
  376 + * added; hint when graphicsmagick is not installed (#62)
  377 + * fixed; minify() (#59)
  378 +
  379 +## v1.3.0 - 04/11/2012
  380 +
  381 + * added; flatten support [jwarchol]
  382 + * added; background support [jwarchol]
  383 + * fixed; identify parser error [chriso]
  384 +
  385 +## v1.2.0 - 03/30/2012
  386 +
  387 + * added; extent and gravity support [jwarchol]
  388 +
  389 +## v1.1.0 - 03/15/2012
  390 +
  391 + * added; filter() support [travisbeck]
  392 + * added; density() [travisbeck]
  393 + * fixed; permit either width or height in resize [dambalah]
  394 + * updated; docs
  395 +
  396 +## v1.0.5 - 02/15/2012
  397 +
  398 + * added; strip() support [Math-]
  399 + * added; interlace() support [Math-]
  400 + * added; setFormat() support [Math-]
  401 + * fixed; regexps for image types [Math-]
  402 +
  403 +## v1.0.4 - 02/09/2012
  404 +
  405 + * expose utils
  406 +
  407 +## v1.0.3 - 01/27/2012
  408 +
  409 + * removed; console.log
  410 +
  411 +## v1.0.2 - 01/24/2012
  412 +
  413 + * added; debugging info on parser errors
  414 + * fixed; exports.version
  415 +
  416 +## v1.0.1 - 01/12/2012
  417 +
  418 + * fixed; use of reserved keyword `super` for node v0.5+
  419 +
  420 +## v1.0.0 - 01/12/2012
  421 +
  422 + * added; autoOrient support [kainosnoema] (#21)
  423 + * added; orientation support [kainosnoema] (#21)
  424 + * fixed; identify parser now properly JSON formats all data output by `gm identify` such as IPTC, GPS, Make, etc (#20)
  425 + * added; support for running as imagemagick (#23, #29)
  426 + * added; subclassing support; useful for setting default constructor options like one constructor for ImageMagick, the other for GM
  427 + * added; more tests
  428 + * changed; remove redundant `orientation`, `resolution`, and `filesize` from `this.data` in `indentify()`. Use their uppercase equivalents.
  429 +
  430 +## v0.6.0 - 12/14/2011
  431 +
  432 + * added; stream support [kainosnoema] (#22)
  433 +
  434 +## v0.5.0 - 07/07/2011
  435 +
  436 + * added; gm#trim() support [lepokle]
  437 + * added; gm#inputIs() support
  438 + * fixed; 'geometry does not contain image' error: gh-17
  439 +
  440 +## v0.4.3 - 05/17/2011
  441 +
  442 + * added; bunch of tests
  443 + * fixed; polygon, polyline, bezier drawing bug
  444 +
  445 +## v0.4.2 - 05/10/2011
  446 +
  447 + * added; resize options support
  448 +
  449 +## v0.4.1 - 04/28/2011
  450 +
  451 + * shell args are now escaped (thanks @visionmedia)
  452 + * added; gm.in()
  453 + * added; gm.out()
  454 + * various refactoring
  455 +
  456 +## v0.4.0 - 9/21/2010
  457 +
  458 + * removed deprecated `new` method
  459 + * added drawing docs
  460 +
  461 +## v0.3.2 - 9/06/2010
  462 +
  463 + * new images are now created using same gm() constructor
  464 +
  465 +## v0.3.1 - 9/06/2010
  466 +
  467 + * can now create images from scratch
  468 + * add type method
  469 +
  470 +## v0.3.0 - 8/26/2010
  471 +
  472 + * add drawing api
  473 +
  474 +## v0.2.2 - 8/22/2010
  475 +
  476 + * add quality option to thumb()
  477 + * add teropa to contributors
  478 + * added support for colorspace()
  479 +
  480 +## v0.2.1 - 7/31/2010
  481 +
  482 + * fixed naming conflict. depth() manipulation method renamed bitdepth()
  483 + * added better docs
  484 +
  485 +## v0.2.0 - 7/29/2010
  486 +
  487 +new methods
  488 +
  489 + - swirl
  490 + - spread
  491 + - solarize
  492 + - sharpen
  493 + - roll
  494 + - sepia
  495 + - region
  496 + - raise
  497 + - lower
  498 + - paint
  499 + - noise
  500 + - negative
  501 + - morph
  502 + - median
  503 + - antialias
  504 + - limit
  505 + - label
  506 + - implode
  507 + - gamma
  508 + - enhance
  509 + - equalize
  510 + - emboss
  511 + - edge
  512 + - dither
  513 + - monochrome
  514 + - despeckle
  515 + - depth
  516 + - cycle
  517 + - contrast
  518 + - comment
  519 + - colors
  520 +
  521 +added more default args to several methods
  522 +added more examples
  523 +
  524 +
  525 +## v0.1.2 - 7/28/2010
  526 +
  527 + * refactor project into separate modules
  528 +
  529 +
  530 +## v0.1.1 - 7/27/2010
  531 +
  532 + * add modulate method
  533 + * add colorize method
  534 + * add charcoal method
  535 + * add chop method
  536 + * bug fix in write without a callback
  537 +
  538 +
  539 +## v0.1.0 - 6/27/2010
  540 +
  541 + * no longer supporting mogrify
  542 + * add image data getter methods
  543 +
  544 + * size
  545 + * format
  546 + * color
  547 + * res
  548 + * depth
  549 + * filesize
  550 + * identify
  551 +
  552 + * add new convert methods
  553 +
  554 + * scale
  555 + * resample
  556 + * rotate
  557 + * flip
  558 + * flop
  559 + * crop
  560 + * magnify
  561 + * minify
  562 + * quality
  563 + * blur
  564 + * thumb
  565 +
  566 +
  567 +## v0.0.1 - 6/11/2010
  568 +Initial release
  1 +
  2 +test:
  3 + @node test/ --integration $(TESTS)
  4 +
  5 +test-unit:
  6 + @node test/ $(TESTS)
  7 +
  8 +.PHONY: test test-unit
  1 +
  2 +# gm [![Build Status](https://travis-ci.org/aheckmann/gm.png?branch=master)](https://travis-ci.org/aheckmann/gm) [![NPM Version](https://img.shields.io/npm/v/gm.svg?style=flat)](https://www.npmjs.org/package/gm)
  3 +
  4 +GraphicsMagick and ImageMagick for node
  5 +
  6 +## Bug Reports
  7 +
  8 +When reporting bugs please include the version of graphicsmagick/imagemagick you're using (gm -version/convert -version) as well as the version of this module and copies of any images you're having problems with.
  9 +
  10 +## Getting started
  11 +First download and install [GraphicsMagick](http://www.graphicsmagick.org/) or [ImageMagick](http://www.imagemagick.org/). In Mac OS X, you can simply use [Homebrew](http://mxcl.github.io/homebrew/) and do:
  12 +
  13 + brew install imagemagick
  14 + brew install graphicsmagick
  15 +
  16 +If you want WebP support with ImageMagick, you must add the WebP option:
  17 +
  18 + brew install imagemagick --with-webp
  19 +
  20 +then either use npm:
  21 +
  22 + npm install gm
  23 +
  24 +or clone the repo:
  25 +
  26 + git clone git://github.com/aheckmann/gm.git
  27 +
  28 +
  29 +## Use ImageMagick instead of gm
  30 +
  31 +Subclass `gm` to enable ImageMagick
  32 +
  33 +```js
  34 +var fs = require('fs')
  35 + , gm = require('gm').subClass({imageMagick: true});
  36 +
  37 +// resize and remove EXIF profile data
  38 +gm('/path/to/my/img.jpg')
  39 +.resize(240, 240)
  40 +...
  41 +```
  42 +
  43 +
  44 +## Basic Usage
  45 +
  46 +```js
  47 +var fs = require('fs')
  48 + , gm = require('gm');
  49 +
  50 +// resize and remove EXIF profile data
  51 +gm('/path/to/my/img.jpg')
  52 +.resize(240, 240)
  53 +.noProfile()
  54 +.write('/path/to/resize.png', function (err) {
  55 + if (!err) console.log('done');
  56 +});
  57 +
  58 +// some files would not be resized appropriately
  59 +// http://stackoverflow.com/questions/5870466/imagemagick-incorrect-dimensions
  60 +// you have two options:
  61 +// use the '!' flag to ignore aspect ratio
  62 +gm('/path/to/my/img.jpg')
  63 +.resize(240, 240, '!')
  64 +.write('/path/to/resize.png', function (err) {
  65 + if (!err) console.log('done');
  66 +});
  67 +
  68 +// use the .resizeExact with only width and/or height arguments
  69 +gm('/path/to/my/img.jpg')
  70 +.resizeExact(240, 240)
  71 +.write('/path/to/resize.png', function (err) {
  72 + if (!err) console.log('done');
  73 +});
  74 +
  75 +// obtain the size of an image
  76 +gm('/path/to/my/img.jpg')
  77 +.size(function (err, size) {
  78 + if (!err)
  79 + console.log(size.width > size.height ? 'wider' : 'taller than you');
  80 +});
  81 +
  82 +// output all available image properties
  83 +gm('/path/to/img.png')
  84 +.identify(function (err, data) {
  85 + if (!err) console.log(data)
  86 +});
  87 +
  88 +// pull out the first frame of an animated gif and save as png
  89 +gm('/path/to/animated.gif[0]')
  90 +.write('/path/to/firstframe.png', function (err) {
  91 + if (err) console.log('aaw, shucks');
  92 +});
  93 +
  94 +// auto-orient an image
  95 +gm('/path/to/img.jpg')
  96 +.autoOrient()
  97 +.write('/path/to/oriented.jpg', function (err) {
  98 + if (err) ...
  99 +})
  100 +
  101 +// crazytown
  102 +gm('/path/to/my/img.jpg')
  103 +.flip()
  104 +.magnify()
  105 +.rotate('green', 45)
  106 +.blur(7, 3)
  107 +.crop(300, 300, 150, 130)
  108 +.edge(3)
  109 +.write('/path/to/crazy.jpg', function (err) {
  110 + if (!err) console.log('crazytown has arrived');
  111 +})
  112 +
  113 +// annotate an image
  114 +gm('/path/to/my/img.jpg')
  115 +.stroke("#ffffff")
  116 +.drawCircle(10, 10, 20, 10)
  117 +.font("Helvetica.ttf", 12)
  118 +.drawText(30, 20, "GMagick!")
  119 +.write("/path/to/drawing.png", function (err) {
  120 + if (!err) console.log('done');
  121 +});
  122 +
  123 +// creating an image
  124 +gm(200, 400, "#ddff99f3")
  125 +.drawText(10, 50, "from scratch")
  126 +.write("/path/to/brandNewImg.jpg", function (err) {
  127 + // ...
  128 +});
  129 +```
  130 +
  131 +## Streams
  132 +
  133 +```js
  134 +// passing a stream
  135 +var readStream = fs.createReadStream('/path/to/my/img.jpg');
  136 +gm(readStream, 'img.jpg')
  137 +.write('/path/to/reformat.png', function (err) {
  138 + if (!err) console.log('done');
  139 +});
  140 +
  141 +
  142 +// passing a downloadable image by url
  143 +
  144 +var request = require('request');
  145 +var url = "www.abc.com/pic.jpg"
  146 +
  147 +gm(request(url))
  148 +.write('/path/to/reformat.png', function (err) {
  149 + if (!err) console.log('done');
  150 +});
  151 +
  152 +
  153 +// can also stream output to a ReadableStream
  154 +// (can be piped to a local file or remote server)
  155 +gm('/path/to/my/img.jpg')
  156 +.resize('200', '200')
  157 +.stream(function (err, stdout, stderr) {
  158 + var writeStream = fs.createWriteStream('/path/to/my/resized.jpg');
  159 + stdout.pipe(writeStream);
  160 +});
  161 +
  162 +// without a callback, .stream() returns a stream
  163 +// this is just a convenience wrapper for above.
  164 +var writeStream = fs.createWriteStream('/path/to/my/resized.jpg');
  165 +gm('/path/to/my/img.jpg')
  166 +.resize('200', '200')
  167 +.stream()
  168 +.pipe(writeStream);
  169 +
  170 +// pass a format or filename to stream() and
  171 +// gm will provide image data in that format
  172 +gm('/path/to/my/img.jpg')
  173 +.stream('png', function (err, stdout, stderr) {
  174 + var writeStream = fs.createWriteStream('/path/to/my/reformatted.png');
  175 + stdout.pipe(writeStream);
  176 +});
  177 +
  178 +// or without the callback
  179 +var writeStream = fs.createWriteStream('/path/to/my/reformatted.png');
  180 +gm('/path/to/my/img.jpg')
  181 +.stream('png')
  182 +.pipe(writeStream);
  183 +
  184 +// combine the two for true streaming image processing
  185 +var readStream = fs.createReadStream('/path/to/my/img.jpg');
  186 +gm(readStream)
  187 +.resize('200', '200')
  188 +.stream(function (err, stdout, stderr) {
  189 + var writeStream = fs.createWriteStream('/path/to/my/resized.jpg');
  190 + stdout.pipe(writeStream);
  191 +});
  192 +
  193 +// GOTCHA:
  194 +// when working with input streams and any 'identify'
  195 +// operation (size, format, etc), you must pass "{bufferStream: true}" if
  196 +// you also need to convert (write() or stream()) the image afterwards
  197 +// NOTE: this buffers the readStream in memory!
  198 +var readStream = fs.createReadStream('/path/to/my/img.jpg');
  199 +gm(readStream)
  200 +.size({bufferStream: true}, function(err, size) {
  201 + this.resize(size.width / 2, size.height / 2)
  202 + this.write('/path/to/resized.jpg', function (err) {
  203 + if (!err) console.log('done');
  204 + });
  205 +});
  206 +
  207 +```
  208 +
  209 +## Buffers
  210 +
  211 +```js
  212 +// A buffer can be passed instead of a filepath as well
  213 +var buf = require('fs').readFileSync('/path/to/image.jpg');
  214 +
  215 +gm(buf, 'image.jpg')
  216 +.noise('laplacian')
  217 +.write('/path/to/out.jpg', function (err) {
  218 + if (err) return handle(err);
  219 + console.log('Created an image from a Buffer!');
  220 +});
  221 +
  222 +/*
  223 +A buffer can also be returned instead of a stream
  224 +The first argument to toBuffer is optional, it specifies the image format
  225 +*/
  226 +gm('img.jpg')
  227 +.resize(100, 100)
  228 +.toBuffer('PNG',function (err, buffer) {
  229 + if (err) return handle(err);
  230 + console.log('done!');
  231 +})
  232 +```
  233 +
  234 +## Custom Arguments
  235 +
  236 +If `gm` does not supply you with a method you need or does not work as you'd like, you can simply use `gm().in()` or `gm().out()` to set your own arguments.
  237 +
  238 +- `gm().command()` - Custom command such as `identify` or `convert`
  239 +- `gm().in()` - Custom input arguments
  240 +- `gm().out()` - Custom output arguments
  241 +
  242 +The command will be formatted in the following order:
  243 +
  244 +1. `command` - ie `convert`
  245 +2. `in` - the input arguments
  246 +3. `source` - stdin or an image file
  247 +4. `out` - the output arguments
  248 +5. `output` - stdout or the image file to write to
  249 +
  250 +For example, suppose you want the following command:
  251 +
  252 +```bash
  253 +gm "convert" "label:Offline" "PNG:-"
  254 +```
  255 +
  256 +However, using `gm().label()` may not work as intended for you:
  257 +
  258 +```js
  259 +gm()
  260 +.label('Offline')
  261 +.stream();
  262 +```
  263 +
  264 +would yield:
  265 +
  266 +```bash
  267 +gm "convert" "-label" "\"Offline\"" "PNG:-"
  268 +```
  269 +
  270 +Instead, you can use `gm().out()`:
  271 +
  272 +```js
  273 +gm()
  274 +.out('label:Offline')
  275 +.stream();
  276 +```
  277 +
  278 +which correctly yields:
  279 +
  280 +```bash
  281 +gm "convert" "label:Offline" "PNG:-"
  282 +```
  283 +
  284 +### Custom Identify Format String
  285 +
  286 +When identifying an image, you may want to use a custom formatting string instead of using `-verbose`, which is quite slow.
  287 +You can use your own [formatting string](http://www.imagemagick.org/script/escape.php) when using `gm().identify(format, callback)`.
  288 +For example,
  289 +
  290 +```js
  291 +gm('img.png').format(function (err, format) {
  292 +
  293 +})
  294 +
  295 +// is equivalent to
  296 +
  297 +gm('img.png').identify('%m', function (err, format) {
  298 +
  299 +})
  300 +```
  301 +
  302 +since `%m` is the format option for getting the image file format.
  303 +
  304 +## Platform differences
  305 +
  306 +Please document and refer to any [platform or ImageMagick/GraphicsMagick issues/differences here](https://github.com/aheckmann/gm/wiki/GraphicsMagick-and-ImageMagick-versions).
  307 +
  308 +## Examples:
  309 +
  310 + Check out the [examples](http://github.com/aheckmann/gm/tree/master/examples/) directory to play around.
  311 + Also take a look at the [extending gm](http://wiki.github.com/aheckmann/gm/extending-gm)
  312 + page to see how to customize gm to your own needs.
  313 +
  314 +## Constructor:
  315 +
  316 + There are a few ways you can use the `gm` image constructor.
  317 +
  318 + - 1) `gm(path)` When you pass a string as the first argument it is interpreted as the path to an image you intend to manipulate.
  319 + - 2) `gm(stream || buffer, [filename])` You may also pass a ReadableStream or Buffer as the first argument, with an optional file name for format inference.
  320 + - 3) `gm(width, height, [color])` When you pass two integer arguments, gm will create a new image on the fly with the provided dimensions and an optional background color. And you can still chain just like you do with pre-existing images too. See [here](http://github.com/aheckmann/gm/blob/master/examples/new.js) for an example.
  321 +
  322 +The links below refer to an older version of gm but everything should still work, if anyone feels like updating them please make a PR
  323 +
  324 +## Methods
  325 +
  326 + - getters
  327 + - [size](http://aheckmann.github.com/gm/docs.html#getters) - returns the size (WxH) of the image
  328 + - [orientation](http://aheckmann.github.com/gm/docs.html#getters) - returns the EXIF orientation of the image
  329 + - [format](http://aheckmann.github.com/gm/docs.html#getters) - returns the image format (gif, jpeg, png, etc)
  330 + - [depth](http://aheckmann.github.com/gm/docs.html#getters) - returns the image color depth
  331 + - [color](http://aheckmann.github.com/gm/docs.html#getters) - returns the number of colors
  332 + - [res](http://aheckmann.github.com/gm/docs.html#getters) - returns the image resolution
  333 + - [filesize](http://aheckmann.github.com/gm/docs.html#getters) - returns image filesize
  334 + - [identify](http://aheckmann.github.com/gm/docs.html#getters) - returns all image data available. Takes an optional format string.
  335 +
  336 + - manipulation
  337 + - [adjoin](http://aheckmann.github.com/gm/docs.html#adjoin)
  338 + - [affine](http://aheckmann.github.com/gm/docs.html#affine)
  339 + - [antialias](http://aheckmann.github.com/gm/docs.html#antialias)
  340 + - [append](http://aheckmann.github.com/gm/docs.html#append)
  341 + - [authenticate](http://aheckmann.github.com/gm/docs.html#authenticate)
  342 + - [autoOrient](http://aheckmann.github.com/gm/docs.html#autoOrient)
  343 + - [average](http://aheckmann.github.com/gm/docs.html#average)
  344 + - [backdrop](http://aheckmann.github.com/gm/docs.html#backdrop)
  345 + - [bitdepth](http://aheckmann.github.com/gm/docs.html#bitdepth)
  346 + - [blackThreshold](http://aheckmann.github.com/gm/docs.html#blackThreshold)
  347 + - [bluePrimary](http://aheckmann.github.com/gm/docs.html#bluePrimary)
  348 + - [blur](http://aheckmann.github.com/gm/docs.html#blur)
  349 + - [border](http://aheckmann.github.com/gm/docs.html#border)
  350 + - [borderColor](http://aheckmann.github.com/gm/docs.html#borderColor)
  351 + - [box](http://aheckmann.github.com/gm/docs.html#box)
  352 + - [channel](http://aheckmann.github.com/gm/docs.html#channel)
  353 + - [charcoal](http://aheckmann.github.com/gm/docs.html#charcoal)
  354 + - [chop](http://aheckmann.github.com/gm/docs.html#chop)
  355 + - [clip](http://aheckmann.github.com/gm/docs.html#clip)
  356 + - [coalesce](http://aheckmann.github.com/gm/docs.html#coalesce)
  357 + - [colors](http://aheckmann.github.com/gm/docs.html#colors)
  358 + - [colorize](http://aheckmann.github.com/gm/docs.html#colorize)
  359 + - [colorMap](http://aheckmann.github.com/gm/docs.html#colorMap)
  360 + - [colorspace](http://aheckmann.github.com/gm/docs.html#colorspace)
  361 + - [comment](http://aheckmann.github.com/gm/docs.html#comment)
  362 + - [compose](http://aheckmann.github.com/gm/docs.html#compose)
  363 + - [compress](http://aheckmann.github.com/gm/docs.html#compress)
  364 + - [contrast](http://aheckmann.github.com/gm/docs.html#contrast)
  365 + - [convolve](http://aheckmann.github.com/gm/docs.html#convolve)
  366 + - [createDirectories](http://aheckmann.github.com/gm/docs.html#createDirectories)
  367 + - [crop](http://aheckmann.github.com/gm/docs.html#crop)
  368 + - [cycle](http://aheckmann.github.com/gm/docs.html#cycle)
  369 + - [deconstruct](http://aheckmann.github.com/gm/docs.html#deconstruct)
  370 + - [delay](http://aheckmann.github.com/gm/docs.html#delay)
  371 + - [define](http://aheckmann.github.com/gm/docs.html#define)
  372 + - [density](http://aheckmann.github.com/gm/docs.html#density)
  373 + - [despeckle](http://aheckmann.github.com/gm/docs.html#despeckle)
  374 + - [dither](http://aheckmann.github.com/gm/docs.html#dither)
  375 + - [displace](http://aheckmann.github.com/gm/docs.html#dither)
  376 + - [display](http://aheckmann.github.com/gm/docs.html#display)
  377 + - [dispose](http://aheckmann.github.com/gm/docs.html#dispose)
  378 + - [dissolve](http://aheckmann.github.com/gm/docs.html#dissolve)
  379 + - [edge](http://aheckmann.github.com/gm/docs.html#edge)
  380 + - [emboss](http://aheckmann.github.com/gm/docs.html#emboss)
  381 + - [encoding](http://aheckmann.github.com/gm/docs.html#encoding)
  382 + - [enhance](http://aheckmann.github.com/gm/docs.html#enhance)
  383 + - [endian](http://aheckmann.github.com/gm/docs.html#endian)
  384 + - [equalize](http://aheckmann.github.com/gm/docs.html#equalize)
  385 + - [extent](http://aheckmann.github.com/gm/docs.html#extent)
  386 + - [file](http://aheckmann.github.com/gm/docs.html#file)
  387 + - [filter](http://aheckmann.github.com/gm/docs.html#filter)
  388 + - [flatten](http://aheckmann.github.com/gm/docs.html#flatten)
  389 + - [flip](http://aheckmann.github.com/gm/docs.html#flip)
  390 + - [flop](http://aheckmann.github.com/gm/docs.html#flop)
  391 + - [foreground](http://aheckmann.github.com/gm/docs.html#foreground)
  392 + - [frame](http://aheckmann.github.com/gm/docs.html#frame)
  393 + - [fuzz](http://aheckmann.github.com/gm/docs.html#fuzz)
  394 + - [gamma](http://aheckmann.github.com/gm/docs.html#gamma)
  395 + - [gaussian](http://aheckmann.github.com/gm/docs.html#gaussian)
  396 + - [geometry](http://aheckmann.github.com/gm/docs.html#geometry)
  397 + - [gravity](http://aheckmann.github.com/gm/docs.html#gravity)
  398 + - [greenPrimary](http://aheckmann.github.com/gm/docs.html#greenPrimary)
  399 + - [highlightColor](http://aheckmann.github.com/gm/docs.html#highlightColor)
  400 + - [highlightStyle](http://aheckmann.github.com/gm/docs.html#highlightStyle)
  401 + - [iconGeometry](http://aheckmann.github.com/gm/docs.html#iconGeometry)
  402 + - [implode](http://aheckmann.github.com/gm/docs.html#implode)
  403 + - [intent](http://aheckmann.github.com/gm/docs.html#intent)
  404 + - [interlace](http://aheckmann.github.com/gm/docs.html#interlace)
  405 + - [label](http://aheckmann.github.com/gm/docs.html#label)
  406 + - [lat](http://aheckmann.github.com/gm/docs.html#lat)
  407 + - [level](http://aheckmann.github.com/gm/docs.html#level)
  408 + - [list](http://aheckmann.github.com/gm/docs.html#list)
  409 + - [limit](http://aheckmann.github.com/gm/docs.html#limit)
  410 + - [log](http://aheckmann.github.com/gm/docs.html#log)
  411 + - [loop](http://aheckmann.github.com/gm/docs.html#loop)
  412 + - [lower](http://aheckmann.github.com/gm/docs.html#lower)
  413 + - [magnify](http://aheckmann.github.com/gm/docs.html#magnify)
  414 + - [map](http://aheckmann.github.com/gm/docs.html#map)
  415 + - [matte](http://aheckmann.github.com/gm/docs.html#matte)
  416 + - [matteColor](http://aheckmann.github.com/gm/docs.html#matteColor)
  417 + - [mask](http://aheckmann.github.com/gm/docs.html#mask)
  418 + - [maximumError](http://aheckmann.github.com/gm/docs.html#maximumError)
  419 + - [median](http://aheckmann.github.com/gm/docs.html#median)
  420 + - [minify](http://aheckmann.github.com/gm/docs.html#minify)
  421 + - [mode](http://aheckmann.github.com/gm/docs.html#mode)
  422 + - [modulate](http://aheckmann.github.com/gm/docs.html#modulate)
  423 + - [monitor](http://aheckmann.github.com/gm/docs.html#monitor)
  424 + - [monochrome](http://aheckmann.github.com/gm/docs.html#monochrome)
  425 + - [morph](http://aheckmann.github.com/gm/docs.html#morph)
  426 + - [mosaic](http://aheckmann.github.com/gm/docs.html#mosaic)
  427 + - [motionBlur](http://aheckmann.github.com/gm/docs.html#motionBlur)
  428 + - [name](http://aheckmann.github.com/gm/docs.html#name)
  429 + - [negative](http://aheckmann.github.com/gm/docs.html#negative)
  430 + - [noise](http://aheckmann.github.com/gm/docs.html#noise)
  431 + - [noop](http://aheckmann.github.com/gm/docs.html#noop)
  432 + - [normalize](http://aheckmann.github.com/gm/docs.html#normalize)
  433 + - [noProfile](http://aheckmann.github.com/gm/docs.html#profile)
  434 + - [opaque](http://aheckmann.github.com/gm/docs.html#opaque)
  435 + - [operator](http://aheckmann.github.com/gm/docs.html#operator)
  436 + - [orderedDither](http://aheckmann.github.com/gm/docs.html#orderedDither)
  437 + - [outputDirectory](http://aheckmann.github.com/gm/docs.html#outputDirectory)
  438 + - [paint](http://aheckmann.github.com/gm/docs.html#paint)
  439 + - [page](http://aheckmann.github.com/gm/docs.html#page)
  440 + - [pause](http://aheckmann.github.com/gm/docs.html#pause)
  441 + - [pen](http://aheckmann.github.com/gm/docs.html#pen)
  442 + - [ping](http://aheckmann.github.com/gm/docs.html#ping)
  443 + - [pointSize](http://aheckmann.github.com/gm/docs.html#pointSize)
  444 + - [preview](http://aheckmann.github.com/gm/docs.html#preview)
  445 + - [process](http://aheckmann.github.com/gm/docs.html#process)
  446 + - [profile](http://aheckmann.github.com/gm/docs.html#profile)
  447 + - [progress](http://aheckmann.github.com/gm/docs.html#progress)
  448 + - [quality](http://aheckmann.github.com/gm/docs.html#quality)
  449 + - [raise](http://aheckmann.github.com/gm/docs.html#raise)
  450 + - [rawSize](http://aheckmann.github.com/gm/docs.html#rawSize)
  451 + - [randomThreshold](http://aheckmann.github.com/gm/docs.html#randomThreshold)
  452 + - [recolor](http://aheckmann.github.com/gm/docs.html#recolor)
  453 + - [redPrimary](http://aheckmann.github.com/gm/docs.html#redPrimary)
  454 + - [region](http://aheckmann.github.com/gm/docs.html#region)
  455 + - [remote](http://aheckmann.github.com/gm/docs.html#remote)
  456 + - [render](http://aheckmann.github.com/gm/docs.html#render)
  457 + - [repage](http://aheckmann.github.com/gm/docs.html#repage)
  458 + - [resample](http://aheckmann.github.com/gm/docs.html#resample)
  459 + - [resize](http://aheckmann.github.com/gm/docs.html#resize)
  460 + - [roll](http://aheckmann.github.com/gm/docs.html#roll)
  461 + - [rotate](http://aheckmann.github.com/gm/docs.html#rotate)
  462 + - [sample](http://aheckmann.github.com/gm/docs.html#sample)
  463 + - [samplingFactor](http://aheckmann.github.com/gm/docs.html#samplingFactor)
  464 + - [scale](http://aheckmann.github.com/gm/docs.html#scale)
  465 + - [scene](http://aheckmann.github.com/gm/docs.html#scene)
  466 + - [scenes](http://aheckmann.github.com/gm/docs.html#scenes)
  467 + - [screen](http://aheckmann.github.com/gm/docs.html#screen)
  468 + - [segment](http://aheckmann.github.com/gm/docs.html#segment)
  469 + - [sepia](http://aheckmann.github.com/gm/docs.html#sepia)
  470 + - [set](http://aheckmann.github.com/gm/docs.html#set)
  471 + - [setFormat](http://aheckmann.github.com/gm/docs.html#setformat)
  472 + - [shade](http://aheckmann.github.com/gm/docs.html#shade)
  473 + - [shadow](http://aheckmann.github.com/gm/docs.html#shadow)
  474 + - [sharedMemory](http://aheckmann.github.com/gm/docs.html#sharedMemory)
  475 + - [sharpen](http://aheckmann.github.com/gm/docs.html#sharpen)
  476 + - [shave](http://aheckmann.github.com/gm/docs.html#shave)
  477 + - [shear](http://aheckmann.github.com/gm/docs.html#shear)
  478 + - [silent](http://aheckmann.github.com/gm/docs.html#silent)
  479 + - [solarize](http://aheckmann.github.com/gm/docs.html#solarize)
  480 + - [snaps](http://aheckmann.github.com/gm/docs.html#snaps)
  481 + - [stegano](http://aheckmann.github.com/gm/docs.html#stegano)
  482 + - [stereo](http://aheckmann.github.com/gm/docs.html#stereo)
  483 + - [strip](http://aheckmann.github.com/gm/docs.html#strip) _imagemagick only_
  484 + - [spread](http://aheckmann.github.com/gm/docs.html#spread)
  485 + - [swirl](http://aheckmann.github.com/gm/docs.html#swirl)
  486 + - [textFont](http://aheckmann.github.com/gm/docs.html#textFont)
  487 + - [texture](http://aheckmann.github.com/gm/docs.html#texture)
  488 + - [threshold](http://aheckmann.github.com/gm/docs.html#threshold)
  489 + - [thumb](http://aheckmann.github.com/gm/docs.html#thumb)
  490 + - [tile](http://aheckmann.github.com/gm/docs.html#tile)
  491 + - [transform](http://aheckmann.github.com/gm/docs.html#transform)
  492 + - [transparent](http://aheckmann.github.com/gm/docs.html#transparent)
  493 + - [treeDepth](http://aheckmann.github.com/gm/docs.html#treeDepth)
  494 + - [trim](http://aheckmann.github.com/gm/docs.html#trim)
  495 + - [type](http://aheckmann.github.com/gm/docs.html#type)
  496 + - [update](http://aheckmann.github.com/gm/docs.html#update)
  497 + - [units](http://aheckmann.github.com/gm/docs.html#units)
  498 + - [unsharp](http://aheckmann.github.com/gm/docs.html#unsharp)
  499 + - [usePixmap](http://aheckmann.github.com/gm/docs.html#usePixmap)
  500 + - [view](http://aheckmann.github.com/gm/docs.html#view)
  501 + - [virtualPixel](http://aheckmann.github.com/gm/docs.html#virtualPixel)
  502 + - [visual](http://aheckmann.github.com/gm/docs.html#visual)
  503 + - [watermark](http://aheckmann.github.com/gm/docs.html#watermark)
  504 + - [wave](http://aheckmann.github.com/gm/docs.html#wave)
  505 + - [whitePoint](http://aheckmann.github.com/gm/docs.html#whitePoint)
  506 + - [whiteThreshold](http://aheckmann.github.com/gm/docs.html#whiteThreshold)
  507 + - [window](http://aheckmann.github.com/gm/docs.html#window)
  508 + - [windowGroup](http://aheckmann.github.com/gm/docs.html#windowGroup)
  509 +
  510 + - drawing primitives
  511 + - [draw](http://aheckmann.github.com/gm/docs.html#draw)
  512 + - [drawArc](http://aheckmann.github.com/gm/docs.html#drawArc)
  513 + - [drawBezier](http://aheckmann.github.com/gm/docs.html#drawBezier)
  514 + - [drawCircle](http://aheckmann.github.com/gm/docs.html#drawCircle)
  515 + - [drawEllipse](http://aheckmann.github.com/gm/docs.html#drawEllipse)
  516 + - [drawLine](http://aheckmann.github.com/gm/docs.html#drawLine)
  517 + - [drawPoint](http://aheckmann.github.com/gm/docs.html#drawPoint)
  518 + - [drawPolygon](http://aheckmann.github.com/gm/docs.html#drawPolygon)
  519 + - [drawPolyline](http://aheckmann.github.com/gm/docs.html#drawPolyline)
  520 + - [drawRectangle](http://aheckmann.github.com/gm/docs.html#drawRectangle)
  521 + - [drawText](http://aheckmann.github.com/gm/docs.html#drawText)
  522 + - [fill](http://aheckmann.github.com/gm/docs.html#fill)
  523 + - [font](http://aheckmann.github.com/gm/docs.html#font)
  524 + - [fontSize](http://aheckmann.github.com/gm/docs.html#fontSize)
  525 + - [stroke](http://aheckmann.github.com/gm/docs.html#stroke)
  526 + - [strokeWidth](http://aheckmann.github.com/gm/docs.html#strokeWidth)
  527 + - [setDraw](http://aheckmann.github.com/gm/docs.html#setDraw)
  528 +
  529 + - image output
  530 + - **write** - writes the processed image data to the specified filename
  531 + - **stream** - provides a `ReadableStream` with the processed image data
  532 + - **toBuffer** - returns the image as a `Buffer` instead of a stream
  533 +
  534 +##compare
  535 +
  536 +Graphicsmagicks `compare` command is exposed through `gm.compare()`. This allows us to determine if two images can be considered "equal".
  537 +
  538 +Currently `gm.compare` only accepts file paths.
  539 +
  540 + gm.compare(path1, path2 [, options], callback)
  541 +
  542 +```js
  543 +gm.compare('/path/to/image1.jpg', '/path/to/another.png', function (err, isEqual, equality, raw, path1, path2) {
  544 + if (err) return handle(err);
  545 +
  546 + // if the images were considered equal, `isEqual` will be true, otherwise, false.
  547 + console.log('The images were equal: %s', isEqual);
  548 +
  549 + // to see the total equality returned by graphicsmagick we can inspect the `equality` argument.
  550 + console.log('Actual equality: %d', equality);
  551 +
  552 + // inspect the raw output
  553 + console.log(raw);
  554 +
  555 + // print file paths
  556 + console.log(path1, path2);
  557 +})
  558 +```
  559 +
  560 +You may wish to pass a custom tolerance threshold to increase or decrease the default level of `0.4`.
  561 +
  562 +
  563 +```js
  564 +gm.compare('/path/to/image1.jpg', '/path/to/another.png', 1.2, function (err, isEqual) {
  565 + ...
  566 +})
  567 +```
  568 +
  569 +To output a diff image, pass a configuration object to define the diff options and tolerance.
  570 +
  571 +
  572 +```js
  573 +var options = {
  574 + file: '/path/to/diff.png',
  575 + highlightColor: 'yellow',
  576 + tolerance: 0.02
  577 +}
  578 +gm.compare('/path/to/image1.jpg', '/path/to/another.png', options, function (err, isEqual, equality, raw) {
  579 + ...
  580 +})
  581 +```
  582 +
  583 +##composite
  584 +
  585 +GraphicsMagick supports compositing one image on top of another. This is exposed through `gm.composite()`. Its first argument is an image path with the changes to the base image, and an optional mask image.
  586 +
  587 +Currently, `gm.composite()` only accepts file paths.
  588 +
  589 + gm.composite(other [, mask])
  590 +
  591 +```js
  592 +gm('/path/to/image.jpg')
  593 +.composite('/path/to/second_image.jpg')
  594 +.geometry('+100+150')
  595 +.write('/path/to/composite.png', function(err) {
  596 + if(!err) console.log("Written composite image.");
  597 +});
  598 +```
  599 +
  600 +##montage
  601 +
  602 +GraphicsMagick supports montage for combining images side by side. This is exposed through `gm.montage()`. Its only argument is an image path with the changes to the base image.
  603 +
  604 +Currently, `gm.montage()` only accepts file paths.
  605 +
  606 + gm.montage(other)
  607 +
  608 +```js
  609 +gm('/path/to/image.jpg')
  610 +.montage('/path/to/second_image.jpg')
  611 +.geometry('+100+150')
  612 +.write('/path/to/montage.png', function(err) {
  613 + if(!err) console.log("Written montage image.");
  614 +});
  615 +```
  616 +
  617 +## Contributors
  618 +[https://github.com/aheckmann/gm/contributors](https://github.com/aheckmann/gm/contributors)
  619 +
  620 +## Inspiration
  621 +http://github.com/quiiver/magickal-node
  622 +
  623 +## Plugins
  624 +[https://github.com/aheckmann/gm/wiki](https://github.com/aheckmann/gm/wiki)
  625 +
  626 +## License
  627 +
  628 +(The MIT License)
  629 +
  630 +Copyright (c) 2010 [Aaron Heckmann](aaron.heckmann+github@gmail.com)
  631 +
  632 +Permission is hereby granted, free of charge, to any person obtaining
  633 +a copy of this software and associated documentation files (the
  634 +'Software'), to deal in the Software without restriction, including
  635 +without limitation the rights to use, copy, modify, merge, publish,
  636 +distribute, sublicense, and/or sell copies of the Software, and to
  637 +permit persons to whom the Software is furnished to do so, subject to
  638 +the following conditions:
  639 +
  640 +The above copyright notice and this permission notice shall be
  641 +included in all copies or substantial portions of the Software.
  642 +
  643 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
  644 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  645 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  646 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  647 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  648 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  649 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  1 +
  2 +/**
  3 + * Module dependencies.
  4 + */
  5 +
  6 +var Stream = require('stream').Stream;
  7 +var EventEmitter = require('events').EventEmitter;
  8 +var util = require('util');
  9 +
  10 +util.inherits(gm, EventEmitter);
  11 +
  12 +/**
  13 + * Constructor.
  14 + *
  15 + * @param {String|Number} path - path to img source or ReadableStream or width of img to create
  16 + * @param {Number} [height] - optional filename of ReadableStream or height of img to create
  17 + * @param {String} [color] - optional hex background color of created img
  18 + */
  19 +
  20 +function gm (source, height, color) {
  21 + var width;
  22 +
  23 + if (!(this instanceof gm)) {
  24 + return new gm(source, height, color);
  25 + }
  26 +
  27 + EventEmitter.call(this);
  28 +
  29 + this._options = {};
  30 + this.options(this.__proto__._options);
  31 +
  32 + this.data = {};
  33 + this._in = [];
  34 + this._out = [];
  35 + this._outputFormat = null;
  36 + this._subCommand = 'convert';
  37 +
  38 + if (source instanceof Stream) {
  39 + this.sourceStream = source;
  40 + source = height || 'unknown.jpg';
  41 + } else if (Buffer.isBuffer(source)) {
  42 + this.sourceBuffer = source;
  43 + source = height || 'unknown.jpg';
  44 + } else if (height) {
  45 + // new images
  46 + width = source;
  47 + source = "";
  48 +
  49 + this.in("-size", width + "x" + height);
  50 +
  51 + if (color) {
  52 + this.in("xc:"+ color);
  53 + }
  54 + }
  55 +
  56 + if (typeof source === "string") {
  57 + // then source is a path
  58 +
  59 + // parse out gif frame brackets from filename
  60 + // since stream doesn't use source path
  61 + // eg. "filename.gif[0]"
  62 + var frames = source.match(/(\[.+\])$/);
  63 + if (frames) {
  64 + this.sourceFrames = source.substr(frames.index, frames[0].length);
  65 + source = source.substr(0, frames.index);
  66 + }
  67 + }
  68 +
  69 + this.source = source;
  70 +
  71 + this.addSrcFormatter(function (src) {
  72 + // must be first source formatter
  73 +
  74 + var inputFromStdin = this.sourceStream || this.sourceBuffer;
  75 + var ret = inputFromStdin ? '-' : this.source;
  76 +
  77 + if (ret && this.sourceFrames) ret += this.sourceFrames;
  78 +
  79 + src.length = 0;
  80 + src[0] = ret;
  81 + });
  82 +}
  83 +
  84 +/**
  85 + * Subclasses the gm constructor with custom options.
  86 + *
  87 + * @param {options} options
  88 + * @return {gm} the subclasses gm constructor
  89 + */
  90 +
  91 +var parent = gm;
  92 +gm.subClass = function subClass (options) {
  93 + function gm (source, height, color) {
  94 + if (!(this instanceof parent)) {
  95 + return new gm(source, height, color);
  96 + }
  97 +
  98 + parent.call(this, source, height, color);
  99 + }
  100 +
  101 + gm.prototype.__proto__ = parent.prototype;
  102 + gm.prototype._options = {};
  103 + gm.prototype.options(options);
  104 +
  105 + return gm;
  106 +}
  107 +
  108 +/**
  109 + * Augment the prototype.
  110 + */
  111 +
  112 +require("./lib/options")(gm.prototype);
  113 +require("./lib/getters")(gm);
  114 +require("./lib/args")(gm.prototype);
  115 +require("./lib/drawing")(gm.prototype);
  116 +require("./lib/convenience")(gm.prototype);
  117 +require("./lib/command")(gm.prototype);
  118 +require("./lib/compare")(gm.prototype);
  119 +require("./lib/composite")(gm.prototype);
  120 +require("./lib/montage")(gm.prototype);
  121 +
  122 +/**
  123 + * Expose.
  124 + */
  125 +
  126 +module.exports = exports = gm;
  127 +module.exports.utils = require('./lib/utils');
  128 +module.exports.compare = require('./lib/compare')();
  129 +module.exports.version = require('./package.json').version;