kimkyeonghun

ver2

Showing 687 changed files with 4793 additions and 0 deletions
1 +MIT License
2 +
3 +Copyright (c) 2017 Jayde-Im
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
1 + ,'''''',
2 + ''''''''''''''
3 + ''''' '''''''''''.
4 + '''' ''''''''''''
5 + '''' ;' '''',
6 + ''': :'''
7 + '':. `.;'
8 + ''''''''; ,''''''''
9 + '''''''''''''; .''''''''''''',
10 + ,''''': '''''''' ,''''''' .''''''
11 + '''', ,''''';'''''' '''',
12 + :'''' `'''''''; ,''''
13 + :'''' ''''''' ,''''
14 + ::::` ;::::::::::` ::::.
15 + ,;;;;;. .;;;;;;; ;;;;;;;: ;;;;;;
16 + ;;;;;;;;;;;;;; :;;;;;;;;;;;;;:
17 + ;;;;;;;;; :;;;;;;;;` GOORM IDE
18 +
19 +
20 +README
21 +
22 +기본적으로 개인별 포트는 3개가 주어집니다. 포트는 생성시기마다 다르게 주어질 수 있으므로, 다음과 같이 사용하시기 바랍니다.
23 +
24 +Node.js에서 실행하는 기본포트는 아래 변수를 통해 자동으로 연결됩니다.
25 +process.env.PORT
26 +
27 +사용 예제)
28 +var app = express();
29 +var port = process.env.PORT || 3000;
30 +http.createServer(app).listen(port, function(){
31 + console.log("Express server listening on port " + port);
32 +});
33 +
34 +추가적인 PORT 필요시 아래 변수를 사용할 수 있습니다.
35 +process.env.PORT2
36 +process.env.PORT3
1 +# nodejs-todo-list
2 +Simple to-do Node.js web application using Express and jQuery.
3 +
4 +This is a sample project for lecture, **[TODO 앱을 직접 만들면서 배우는 node.js / express / bootstrap / jquery](http://edu.goorm.io/lecture/bGVjX3pOZmhrXzE0NzMzMjIyOTMzODI=)** in [goormEDU](http://edu.goorm.io/index)
5 +
6 +
7 +
8 +## How to start
9 +
10 +0. Install [Node.js](https://nodejs.org/en/):
11 +
12 +- Binaries, installers, and source tarballs are available at <https://nodejs.org/en/download/>.
13 +- Install suitable version for your platform.
14 +
15 +1. Download the project:
16 +
17 +- Download ZIP
18 +or
19 +- Clone the repo:
20 +```console
21 +$ git clone https://github.com/Jayde-Im/nodejs-todo-list.git
22 +```
23 +
24 +2. Go to project directory and install dependencies:
25 +
26 +```console
27 +$ cd nodejs-todo-list
28 +```
29 +```console
30 +$ npm install
31 +```
32 +
33 +3. Run the application:
34 +
35 +```console
36 +$ npm start
37 +```
38 +
39 +
40 +4. Open a browser and go to `localhost:3000`.
41 +
42 +
43 +
44 +
45 +
46 +## Report a bug
47 +
48 +If you find bugs or have any questions, [open a new issue](https://github.com/Jayde-Im/nodejs-todo-list/issues), please.
1 + ,'''''',
2 + ''''''''''''''
3 + ''''' '''''''''''.
4 + '''' ''''''''''''
5 + '''' ;' '''',
6 + ''': :'''
7 + '':. `.;'
8 + ''''''''; ,''''''''
9 + '''''''''''''; .''''''''''''',
10 + ,''''': '''''''' ,''''''' .''''''
11 + '''', ,''''';'''''' '''',
12 + :'''' `'''''''; ,''''
13 + :'''' ''''''' ,''''
14 + ::::` ;::::::::::` ::::.
15 + ,;;;;;. .;;;;;;; ;;;;;;;: ;;;;;;
16 + ;;;;;;;;;;;;;; :;;;;;;;;;;;;;:
17 + ;;;;;;;;; :;;;;;;;;` GOORM IDE
18 +
19 +
20 +README
21 +
22 +Basically we give you 3 ports of personal use.
23 +Since these port can be changed for its creating time, please use your port following the direction.
24 +
25 +Default port used by Node.js is automatically connected through this variable.
26 +process.env.PORT
27 +
28 +Examples)
29 +var app = express();
30 +var port = process.env.PORT || 3000;
31 +http.createServer(app).listen(port, function(){
32 +console.log("Express server listening on port " + port);
33 +});
34 +
35 +If you need additional port, you can use other variables below.
36 +process.env.PORT2
37 +process.env.PORT3
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +/**
3 + * Module dependencies.
4 + */
5 +
6 +// 모듈 가져오기
7 +var express = require('express')
8 + , routes = require('./routes')
9 + , todo = require('./routes/todo')
10 + , http = require('http')
11 + , path = require('path');
12 +
13 +var app = express(); // 어플리케이션 생성
14 +var port = 3000; // 어플리케이션 포트
15 +
16 +// 어플리케이션 설정
17 +app.configure(function(){
18 + app.set('port', port); // 웹 서버 포트
19 + app.set('views', __dirname + '/views'); // 템플릿
20 + app.set('view engine', 'ejs'); // 템플릿 엔진
21 + app.use(express.favicon()); // 파비콘
22 + app.use(express.logger('dev')); // 로그 기록
23 + app.use(express.bodyParser()); // 요청 본문 파싱
24 + app.use(express.methodOverride()); // 구식 브라우저 메소드 지원
25 + app.use(app.router); // 라우팅
26 +
27 + // 정적 리소스 처리
28 + app.use(require('stylus').middleware(__dirname + '/public'));
29 + app.use(express.static(path.join(__dirname, 'public')));
30 +});
31 +
32 +app.configure('development', function(){ // 개발 버전
33 + app.use(express.errorHandler()); // 에러 메세지
34 +});
35 +
36 +// 라우팅
37 +app.get('/', routes.index);
38 +app.get('/list', todo.list);
39 +app.post('/add', todo.add);
40 +app.post('/complete', todo.complete);
41 +app.post('/del', todo.del);
42 +app.get('/search',todo.search);
43 +
44 +// 서버 실행
45 +http.createServer(app).listen(app.get('port'), function(){
46 + console.log("Express server listening on port " + app.get('port'));
47 +});
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../express/bin/express" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../express/bin/express" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\express\bin\express" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\express\bin\express" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../stylus/bin/stylus" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../stylus/bin/stylus" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\stylus\bin\stylus" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\stylus\bin\stylus" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +amdefine is released under two licenses: new BSD, and MIT. You may pick the
2 +license that best suits your development needs. The text of both licenses are
3 +provided below.
4 +
5 +
6 +The "New" BSD License:
7 +----------------------
8 +
9 +Copyright (c) 2011-2016, The Dojo Foundation
10 +All rights reserved.
11 +
12 +Redistribution and use in source and binary forms, with or without
13 +modification, are permitted provided that the following conditions are met:
14 +
15 + * Redistributions of source code must retain the above copyright notice, this
16 + list of conditions and the following disclaimer.
17 + * Redistributions in binary form must reproduce the above copyright notice,
18 + this list of conditions and the following disclaimer in the documentation
19 + and/or other materials provided with the distribution.
20 + * Neither the name of the Dojo Foundation nor the names of its contributors
21 + may be used to endorse or promote products derived from this software
22 + without specific prior written permission.
23 +
24 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
28 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 +
35 +
36 +
37 +MIT License
38 +-----------
39 +
40 +Copyright (c) 2011-2016, The Dojo Foundation
41 +
42 +Permission is hereby granted, free of charge, to any person obtaining a copy
43 +of this software and associated documentation files (the "Software"), to deal
44 +in the Software without restriction, including without limitation the rights
45 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
46 +copies of the Software, and to permit persons to whom the Software is
47 +furnished to do so, subject to the following conditions:
48 +
49 +The above copyright notice and this permission notice shall be included in
50 +all copies or substantial portions of the Software.
51 +
52 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
53 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
54 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
55 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
56 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
57 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
58 +THE SOFTWARE.
1 +# amdefine
2 +
3 +A module that can be used to implement AMD's define() in Node. This allows you
4 +to code to the AMD API and have the module work in node programs without
5 +requiring those other programs to use AMD.
6 +
7 +## Usage
8 +
9 +**1)** Update your package.json to indicate amdefine as a dependency:
10 +
11 +```javascript
12 + "dependencies": {
13 + "amdefine": ">=0.1.0"
14 + }
15 +```
16 +
17 +Then run `npm install` to get amdefine into your project.
18 +
19 +**2)** At the top of each module that uses define(), place this code:
20 +
21 +```javascript
22 +if (typeof define !== 'function') { var define = require('amdefine')(module) }
23 +```
24 +
25 +**Only use these snippets** when loading amdefine. If you preserve the basic structure,
26 +with the braces, it will be stripped out when using the [RequireJS optimizer](#optimizer).
27 +
28 +You can add spaces, line breaks and even require amdefine with a local path, but
29 +keep the rest of the structure to get the stripping behavior.
30 +
31 +As you may know, because `if` statements in JavaScript don't have their own scope, the var
32 +declaration in the above snippet is made whether the `if` expression is truthy or not. If
33 +RequireJS is loaded then the declaration is superfluous because `define` is already already
34 +declared in the same scope in RequireJS. Fortunately JavaScript handles multiple `var`
35 +declarations of the same variable in the same scope gracefully.
36 +
37 +If you want to deliver amdefine.js with your code rather than specifying it as a dependency
38 +with npm, then just download the latest release and refer to it using a relative path:
39 +
40 +[Latest Version](https://github.com/jrburke/amdefine/raw/latest/amdefine.js)
41 +
42 +### amdefine/intercept
43 +
44 +Consider this very experimental.
45 +
46 +Instead of pasting the piece of text for the amdefine setup of a `define`
47 +variable in each module you create or consume, you can use `amdefine/intercept`
48 +instead. It will automatically insert the above snippet in each .js file loaded
49 +by Node.
50 +
51 +**Warning**: you should only use this if you are creating an application that
52 +is consuming AMD style defined()'d modules that are distributed via npm and want
53 +to run that code in Node.
54 +
55 +For library code where you are not sure if it will be used by others in Node or
56 +in the browser, then explicitly depending on amdefine and placing the code
57 +snippet above is suggested path, instead of using `amdefine/intercept`. The
58 +intercept module affects all .js files loaded in the Node app, and it is
59 +inconsiderate to modify global state like that unless you are also controlling
60 +the top level app.
61 +
62 +#### Why distribute AMD-style modules via npm?
63 +
64 +npm has a lot of weaknesses for front-end use (installed layout is not great,
65 +should have better support for the `baseUrl + moduleID + '.js' style of loading,
66 +single file JS installs), but some people want a JS package manager and are
67 +willing to live with those constraints. If that is you, but still want to author
68 +in AMD style modules to get dynamic require([]), better direct source usage and
69 +powerful loader plugin support in the browser, then this tool can help.
70 +
71 +#### amdefine/intercept usage
72 +
73 +Just require it in your top level app module (for example index.js, server.js):
74 +
75 +```javascript
76 +require('amdefine/intercept');
77 +```
78 +
79 +The module does not return a value, so no need to assign the result to a local
80 +variable.
81 +
82 +Then just require() code as you normally would with Node's require(). Any .js
83 +loaded after the intercept require will have the amdefine check injected in
84 +the .js source as it is loaded. It does not modify the source on disk, just
85 +prepends some content to the text of the module as it is loaded by Node.
86 +
87 +#### How amdefine/intercept works
88 +
89 +It overrides the `Module._extensions['.js']` in Node to automatically prepend
90 +the amdefine snippet above. So, it will affect any .js file loaded by your
91 +app.
92 +
93 +## define() usage
94 +
95 +It is best if you use the anonymous forms of define() in your module:
96 +
97 +```javascript
98 +define(function (require) {
99 + var dependency = require('dependency');
100 +});
101 +```
102 +
103 +or
104 +
105 +```javascript
106 +define(['dependency'], function (dependency) {
107 +
108 +});
109 +```
110 +
111 +## RequireJS optimizer integration. <a name="optimizer"></name>
112 +
113 +Version 1.0.3 of the [RequireJS optimizer](http://requirejs.org/docs/optimization.html)
114 +will have support for stripping the `if (typeof define !== 'function')` check
115 +mentioned above, so you can include this snippet for code that runs in the
116 +browser, but avoid taking the cost of the if() statement once the code is
117 +optimized for deployment.
118 +
119 +## Node 0.4 Support
120 +
121 +If you want to support Node 0.4, then add `require` as the second parameter to amdefine:
122 +
123 +```javascript
124 +//Only if you want Node 0.4. If using 0.5 or later, use the above snippet.
125 +if (typeof define !== 'function') { var define = require('amdefine')(module, require) }
126 +```
127 +
128 +## Limitations
129 +
130 +### Synchronous vs Asynchronous
131 +
132 +amdefine creates a define() function that is callable by your code. It will
133 +execute and trace dependencies and call the factory function *synchronously*,
134 +to keep the behavior in line with Node's synchronous dependency tracing.
135 +
136 +The exception: calling AMD's callback-style require() from inside a factory
137 +function. The require callback is called on process.nextTick():
138 +
139 +```javascript
140 +define(function (require) {
141 + require(['a'], function(a) {
142 + //'a' is loaded synchronously, but
143 + //this callback is called on process.nextTick().
144 + });
145 +});
146 +```
147 +
148 +### Loader Plugins
149 +
150 +Loader plugins are supported as long as they call their load() callbacks
151 +synchronously. So ones that do network requests will not work. However plugins
152 +like [text](http://requirejs.org/docs/api.html#text) can load text files locally.
153 +
154 +The plugin API's `load.fromText()` is **not supported** in amdefine, so this means
155 +transpiler plugins like the [CoffeeScript loader plugin](https://github.com/jrburke/require-cs)
156 +will not work. This may be fixable, but it is a bit complex, and I do not have
157 +enough node-fu to figure it out yet. See the source for amdefine.js if you want
158 +to get an idea of the issues involved.
159 +
160 +## Tests
161 +
162 +To run the tests, cd to **tests** and run:
163 +
164 +```
165 +node all.js
166 +node all-intercept.js
167 +```
168 +
169 +## License
170 +
171 +New BSD and MIT. Check the LICENSE file for all the details.
1 +/** vim: et:ts=4:sw=4:sts=4
2 + * @license amdefine 1.0.1 Copyright (c) 2011-2016, The Dojo Foundation All Rights Reserved.
3 + * Available via the MIT or new BSD license.
4 + * see: http://github.com/jrburke/amdefine for details
5 + */
6 +
7 +/*jslint node: true */
8 +/*global module, process */
9 +'use strict';
10 +
11 +/**
12 + * Creates a define for node.
13 + * @param {Object} module the "module" object that is defined by Node for the
14 + * current module.
15 + * @param {Function} [requireFn]. Node's require function for the current module.
16 + * It only needs to be passed in Node versions before 0.5, when module.require
17 + * did not exist.
18 + * @returns {Function} a define function that is usable for the current node
19 + * module.
20 + */
21 +function amdefine(module, requireFn) {
22 + 'use strict';
23 + var defineCache = {},
24 + loaderCache = {},
25 + alreadyCalled = false,
26 + path = require('path'),
27 + makeRequire, stringRequire;
28 +
29 + /**
30 + * Trims the . and .. from an array of path segments.
31 + * It will keep a leading path segment if a .. will become
32 + * the first path segment, to help with module name lookups,
33 + * which act like paths, but can be remapped. But the end result,
34 + * all paths that use this function should look normalized.
35 + * NOTE: this method MODIFIES the input array.
36 + * @param {Array} ary the array of path segments.
37 + */
38 + function trimDots(ary) {
39 + var i, part;
40 + for (i = 0; ary[i]; i+= 1) {
41 + part = ary[i];
42 + if (part === '.') {
43 + ary.splice(i, 1);
44 + i -= 1;
45 + } else if (part === '..') {
46 + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
47 + //End of the line. Keep at least one non-dot
48 + //path segment at the front so it can be mapped
49 + //correctly to disk. Otherwise, there is likely
50 + //no path mapping for a path starting with '..'.
51 + //This can still fail, but catches the most reasonable
52 + //uses of ..
53 + break;
54 + } else if (i > 0) {
55 + ary.splice(i - 1, 2);
56 + i -= 2;
57 + }
58 + }
59 + }
60 + }
61 +
62 + function normalize(name, baseName) {
63 + var baseParts;
64 +
65 + //Adjust any relative paths.
66 + if (name && name.charAt(0) === '.') {
67 + //If have a base name, try to normalize against it,
68 + //otherwise, assume it is a top-level require that will
69 + //be relative to baseUrl in the end.
70 + if (baseName) {
71 + baseParts = baseName.split('/');
72 + baseParts = baseParts.slice(0, baseParts.length - 1);
73 + baseParts = baseParts.concat(name.split('/'));
74 + trimDots(baseParts);
75 + name = baseParts.join('/');
76 + }
77 + }
78 +
79 + return name;
80 + }
81 +
82 + /**
83 + * Create the normalize() function passed to a loader plugin's
84 + * normalize method.
85 + */
86 + function makeNormalize(relName) {
87 + return function (name) {
88 + return normalize(name, relName);
89 + };
90 + }
91 +
92 + function makeLoad(id) {
93 + function load(value) {
94 + loaderCache[id] = value;
95 + }
96 +
97 + load.fromText = function (id, text) {
98 + //This one is difficult because the text can/probably uses
99 + //define, and any relative paths and requires should be relative
100 + //to that id was it would be found on disk. But this would require
101 + //bootstrapping a module/require fairly deeply from node core.
102 + //Not sure how best to go about that yet.
103 + throw new Error('amdefine does not implement load.fromText');
104 + };
105 +
106 + return load;
107 + }
108 +
109 + makeRequire = function (systemRequire, exports, module, relId) {
110 + function amdRequire(deps, callback) {
111 + if (typeof deps === 'string') {
112 + //Synchronous, single module require('')
113 + return stringRequire(systemRequire, exports, module, deps, relId);
114 + } else {
115 + //Array of dependencies with a callback.
116 +
117 + //Convert the dependencies to modules.
118 + deps = deps.map(function (depName) {
119 + return stringRequire(systemRequire, exports, module, depName, relId);
120 + });
121 +
122 + //Wait for next tick to call back the require call.
123 + if (callback) {
124 + process.nextTick(function () {
125 + callback.apply(null, deps);
126 + });
127 + }
128 + }
129 + }
130 +
131 + amdRequire.toUrl = function (filePath) {
132 + if (filePath.indexOf('.') === 0) {
133 + return normalize(filePath, path.dirname(module.filename));
134 + } else {
135 + return filePath;
136 + }
137 + };
138 +
139 + return amdRequire;
140 + };
141 +
142 + //Favor explicit value, passed in if the module wants to support Node 0.4.
143 + requireFn = requireFn || function req() {
144 + return module.require.apply(module, arguments);
145 + };
146 +
147 + function runFactory(id, deps, factory) {
148 + var r, e, m, result;
149 +
150 + if (id) {
151 + e = loaderCache[id] = {};
152 + m = {
153 + id: id,
154 + uri: __filename,
155 + exports: e
156 + };
157 + r = makeRequire(requireFn, e, m, id);
158 + } else {
159 + //Only support one define call per file
160 + if (alreadyCalled) {
161 + throw new Error('amdefine with no module ID cannot be called more than once per file.');
162 + }
163 + alreadyCalled = true;
164 +
165 + //Use the real variables from node
166 + //Use module.exports for exports, since
167 + //the exports in here is amdefine exports.
168 + e = module.exports;
169 + m = module;
170 + r = makeRequire(requireFn, e, m, module.id);
171 + }
172 +
173 + //If there are dependencies, they are strings, so need
174 + //to convert them to dependency values.
175 + if (deps) {
176 + deps = deps.map(function (depName) {
177 + return r(depName);
178 + });
179 + }
180 +
181 + //Call the factory with the right dependencies.
182 + if (typeof factory === 'function') {
183 + result = factory.apply(m.exports, deps);
184 + } else {
185 + result = factory;
186 + }
187 +
188 + if (result !== undefined) {
189 + m.exports = result;
190 + if (id) {
191 + loaderCache[id] = m.exports;
192 + }
193 + }
194 + }
195 +
196 + stringRequire = function (systemRequire, exports, module, id, relId) {
197 + //Split the ID by a ! so that
198 + var index = id.indexOf('!'),
199 + originalId = id,
200 + prefix, plugin;
201 +
202 + if (index === -1) {
203 + id = normalize(id, relId);
204 +
205 + //Straight module lookup. If it is one of the special dependencies,
206 + //deal with it, otherwise, delegate to node.
207 + if (id === 'require') {
208 + return makeRequire(systemRequire, exports, module, relId);
209 + } else if (id === 'exports') {
210 + return exports;
211 + } else if (id === 'module') {
212 + return module;
213 + } else if (loaderCache.hasOwnProperty(id)) {
214 + return loaderCache[id];
215 + } else if (defineCache[id]) {
216 + runFactory.apply(null, defineCache[id]);
217 + return loaderCache[id];
218 + } else {
219 + if(systemRequire) {
220 + return systemRequire(originalId);
221 + } else {
222 + throw new Error('No module with ID: ' + id);
223 + }
224 + }
225 + } else {
226 + //There is a plugin in play.
227 + prefix = id.substring(0, index);
228 + id = id.substring(index + 1, id.length);
229 +
230 + plugin = stringRequire(systemRequire, exports, module, prefix, relId);
231 +
232 + if (plugin.normalize) {
233 + id = plugin.normalize(id, makeNormalize(relId));
234 + } else {
235 + //Normalize the ID normally.
236 + id = normalize(id, relId);
237 + }
238 +
239 + if (loaderCache[id]) {
240 + return loaderCache[id];
241 + } else {
242 + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {});
243 +
244 + return loaderCache[id];
245 + }
246 + }
247 + };
248 +
249 + //Create a define function specific to the module asking for amdefine.
250 + function define(id, deps, factory) {
251 + if (Array.isArray(id)) {
252 + factory = deps;
253 + deps = id;
254 + id = undefined;
255 + } else if (typeof id !== 'string') {
256 + factory = id;
257 + id = deps = undefined;
258 + }
259 +
260 + if (deps && !Array.isArray(deps)) {
261 + factory = deps;
262 + deps = undefined;
263 + }
264 +
265 + if (!deps) {
266 + deps = ['require', 'exports', 'module'];
267 + }
268 +
269 + //Set up properties for this module. If an ID, then use
270 + //internal cache. If no ID, then use the external variables
271 + //for this node module.
272 + if (id) {
273 + //Put the module in deep freeze until there is a
274 + //require call for it.
275 + defineCache[id] = [id, deps, factory];
276 + } else {
277 + runFactory(id, deps, factory);
278 + }
279 + }
280 +
281 + //define.require, which has access to all the values in the
282 + //cache. Useful for AMD modules that all have IDs in the file,
283 + //but need to finally export a value to node based on one of those
284 + //IDs.
285 + define.require = function (id) {
286 + if (loaderCache[id]) {
287 + return loaderCache[id];
288 + }
289 +
290 + if (defineCache[id]) {
291 + runFactory.apply(null, defineCache[id]);
292 + return loaderCache[id];
293 + }
294 + };
295 +
296 + define.amd = {};
297 +
298 + return define;
299 +}
300 +
301 +module.exports = amdefine;
1 +/*jshint node: true */
2 +var inserted,
3 + Module = require('module'),
4 + fs = require('fs'),
5 + existingExtFn = Module._extensions['.js'],
6 + amdefineRegExp = /amdefine\.js/;
7 +
8 +inserted = "if (typeof define !== 'function') {var define = require('amdefine')(module)}";
9 +
10 +//From the node/lib/module.js source:
11 +function stripBOM(content) {
12 + // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
13 + // because the buffer-to-string conversion in `fs.readFileSync()`
14 + // translates it to FEFF, the UTF-16 BOM.
15 + if (content.charCodeAt(0) === 0xFEFF) {
16 + content = content.slice(1);
17 + }
18 + return content;
19 +}
20 +
21 +//Also adapted from the node/lib/module.js source:
22 +function intercept(module, filename) {
23 + var content = stripBOM(fs.readFileSync(filename, 'utf8'));
24 +
25 + if (!amdefineRegExp.test(module.id)) {
26 + content = inserted + content;
27 + }
28 +
29 + module._compile(content, filename);
30 +}
31 +
32 +intercept._id = 'amdefine/intercept';
33 +
34 +if (!existingExtFn._id || existingExtFn._id !== intercept._id) {
35 + Module._extensions['.js'] = intercept;
36 +}
1 +{
2 + "_from": "amdefine@>=0.0.4",
3 + "_id": "amdefine@1.0.1",
4 + "_inBundle": false,
5 + "_integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
6 + "_location": "/amdefine",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "amdefine@>=0.0.4",
12 + "name": "amdefine",
13 + "escapedName": "amdefine",
14 + "rawSpec": ">=0.0.4",
15 + "saveSpec": null,
16 + "fetchSpec": ">=0.0.4"
17 + },
18 + "_requiredBy": [
19 + "/source-map"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
22 + "_shasum": "4a5282ac164729e93619bcfd3ad151f817ce91f5",
23 + "_spec": "amdefine@>=0.0.4",
24 + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\source-map",
25 + "author": {
26 + "name": "James Burke",
27 + "email": "jrburke@gmail.com",
28 + "url": "http://github.com/jrburke"
29 + },
30 + "bugs": {
31 + "url": "https://github.com/jrburke/amdefine/issues"
32 + },
33 + "bundleDependencies": false,
34 + "deprecated": false,
35 + "description": "Provide AMD's define() API for declaring modules in the AMD format",
36 + "engines": {
37 + "node": ">=0.4.2"
38 + },
39 + "homepage": "http://github.com/jrburke/amdefine",
40 + "license": "BSD-3-Clause OR MIT",
41 + "main": "./amdefine.js",
42 + "name": "amdefine",
43 + "repository": {
44 + "type": "git",
45 + "url": "git+https://github.com/jrburke/amdefine.git"
46 + },
47 + "version": "1.0.1"
48 +}
1 +test
2 +.gitignore
3 +.travis.yml
4 +Makefile
5 +example.js
1 +(MIT)
2 +
3 +Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy of
6 +this software and associated documentation files (the "Software"), to deal in
7 +the Software without restriction, including without limitation the rights to
8 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 +of the Software, and to permit persons to whom the Software is furnished to do
10 +so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
1 +# balanced-match
2 +
3 +Match balanced string pairs, like `{` and `}` or `<b>` and `</b>`. Supports regular expressions as well!
4 +
5 +[![build status](https://secure.travis-ci.org/juliangruber/balanced-match.svg)](http://travis-ci.org/juliangruber/balanced-match)
6 +[![downloads](https://img.shields.io/npm/dm/balanced-match.svg)](https://www.npmjs.org/package/balanced-match)
7 +
8 +[![testling badge](https://ci.testling.com/juliangruber/balanced-match.png)](https://ci.testling.com/juliangruber/balanced-match)
9 +
10 +## Example
11 +
12 +Get the first matching pair of braces:
13 +
14 +```js
15 +var balanced = require('balanced-match');
16 +
17 +console.log(balanced('{', '}', 'pre{in{nested}}post'));
18 +console.log(balanced('{', '}', 'pre{first}between{second}post'));
19 +console.log(balanced(/\s+\{\s+/, /\s+\}\s+/, 'pre { in{nest} } post'));
20 +```
21 +
22 +The matches are:
23 +
24 +```bash
25 +$ node example.js
26 +{ start: 3, end: 14, pre: 'pre', body: 'in{nested}', post: 'post' }
27 +{ start: 3,
28 + end: 9,
29 + pre: 'pre',
30 + body: 'first',
31 + post: 'between{second}post' }
32 +{ start: 3, end: 17, pre: 'pre', body: 'in{nest}', post: 'post' }
33 +```
34 +
35 +## API
36 +
37 +### var m = balanced(a, b, str)
38 +
39 +For the first non-nested matching pair of `a` and `b` in `str`, return an
40 +object with those keys:
41 +
42 +* **start** the index of the first match of `a`
43 +* **end** the index of the matching `b`
44 +* **pre** the preamble, `a` and `b` not included
45 +* **body** the match, `a` and `b` not included
46 +* **post** the postscript, `a` and `b` not included
47 +
48 +If there's no match, `undefined` will be returned.
49 +
50 +If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `['{', 'a', '']` and `{a}}` will match `['', 'a', '}']`.
51 +
52 +### var r = balanced.range(a, b, str)
53 +
54 +For the first non-nested matching pair of `a` and `b` in `str`, return an
55 +array with indexes: `[ <a index>, <b index> ]`.
56 +
57 +If there's no match, `undefined` will be returned.
58 +
59 +If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `[ 1, 3 ]` and `{a}}` will match `[0, 2]`.
60 +
61 +## Installation
62 +
63 +With [npm](https://npmjs.org) do:
64 +
65 +```bash
66 +npm install balanced-match
67 +```
68 +
69 +## License
70 +
71 +(MIT)
72 +
73 +Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
74 +
75 +Permission is hereby granted, free of charge, to any person obtaining a copy of
76 +this software and associated documentation files (the "Software"), to deal in
77 +the Software without restriction, including without limitation the rights to
78 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
79 +of the Software, and to permit persons to whom the Software is furnished to do
80 +so, subject to the following conditions:
81 +
82 +The above copyright notice and this permission notice shall be included in all
83 +copies or substantial portions of the Software.
84 +
85 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
86 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
87 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
88 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
89 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
90 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
91 +SOFTWARE.
1 +'use strict';
2 +module.exports = balanced;
3 +function balanced(a, b, str) {
4 + if (a instanceof RegExp) a = maybeMatch(a, str);
5 + if (b instanceof RegExp) b = maybeMatch(b, str);
6 +
7 + var r = range(a, b, str);
8 +
9 + return r && {
10 + start: r[0],
11 + end: r[1],
12 + pre: str.slice(0, r[0]),
13 + body: str.slice(r[0] + a.length, r[1]),
14 + post: str.slice(r[1] + b.length)
15 + };
16 +}
17 +
18 +function maybeMatch(reg, str) {
19 + var m = str.match(reg);
20 + return m ? m[0] : null;
21 +}
22 +
23 +balanced.range = range;
24 +function range(a, b, str) {
25 + var begs, beg, left, right, result;
26 + var ai = str.indexOf(a);
27 + var bi = str.indexOf(b, ai + 1);
28 + var i = ai;
29 +
30 + if (ai >= 0 && bi > 0) {
31 + begs = [];
32 + left = str.length;
33 +
34 + while (i >= 0 && !result) {
35 + if (i == ai) {
36 + begs.push(i);
37 + ai = str.indexOf(a, i + 1);
38 + } else if (begs.length == 1) {
39 + result = [ begs.pop(), bi ];
40 + } else {
41 + beg = begs.pop();
42 + if (beg < left) {
43 + left = beg;
44 + right = bi;
45 + }
46 +
47 + bi = str.indexOf(b, i + 1);
48 + }
49 +
50 + i = ai < bi && ai >= 0 ? ai : bi;
51 + }
52 +
53 + if (begs.length) {
54 + result = [ left, right ];
55 + }
56 + }
57 +
58 + return result;
59 +}
1 +{
2 + "_from": "balanced-match@^1.0.0",
3 + "_id": "balanced-match@1.0.0",
4 + "_inBundle": false,
5 + "_integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
6 + "_location": "/balanced-match",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "balanced-match@^1.0.0",
12 + "name": "balanced-match",
13 + "escapedName": "balanced-match",
14 + "rawSpec": "^1.0.0",
15 + "saveSpec": null,
16 + "fetchSpec": "^1.0.0"
17 + },
18 + "_requiredBy": [
19 + "/brace-expansion"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
22 + "_shasum": "89b4d199ab2bee49de164ea02b89ce462d71b767",
23 + "_spec": "balanced-match@^1.0.0",
24 + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\brace-expansion",
25 + "author": {
26 + "name": "Julian Gruber",
27 + "email": "mail@juliangruber.com",
28 + "url": "http://juliangruber.com"
29 + },
30 + "bugs": {
31 + "url": "https://github.com/juliangruber/balanced-match/issues"
32 + },
33 + "bundleDependencies": false,
34 + "dependencies": {},
35 + "deprecated": false,
36 + "description": "Match balanced character pairs, like \"{\" and \"}\"",
37 + "devDependencies": {
38 + "matcha": "^0.7.0",
39 + "tape": "^4.6.0"
40 + },
41 + "homepage": "https://github.com/juliangruber/balanced-match",
42 + "keywords": [
43 + "match",
44 + "regexp",
45 + "test",
46 + "balanced",
47 + "parse"
48 + ],
49 + "license": "MIT",
50 + "main": "index.js",
51 + "name": "balanced-match",
52 + "repository": {
53 + "type": "git",
54 + "url": "git://github.com/juliangruber/balanced-match.git"
55 + },
56 + "scripts": {
57 + "bench": "make bench",
58 + "test": "make test"
59 + },
60 + "testling": {
61 + "files": "test/*.js",
62 + "browsers": [
63 + "ie/8..latest",
64 + "firefox/20..latest",
65 + "firefox/nightly",
66 + "chrome/25..latest",
67 + "chrome/canary",
68 + "opera/12..latest",
69 + "opera/next",
70 + "safari/5.1..latest",
71 + "ipad/6.0..latest",
72 + "iphone/6.0..latest",
73 + "android-browser/4.2..latest"
74 + ]
75 + },
76 + "version": "1.0.0"
77 +}
1 +MIT License
2 +
3 +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
1 +# brace-expansion
2 +
3 +[Brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html),
4 +as known from sh/bash, in JavaScript.
5 +
6 +[![build status](https://secure.travis-ci.org/juliangruber/brace-expansion.svg)](http://travis-ci.org/juliangruber/brace-expansion)
7 +[![downloads](https://img.shields.io/npm/dm/brace-expansion.svg)](https://www.npmjs.org/package/brace-expansion)
8 +[![Greenkeeper badge](https://badges.greenkeeper.io/juliangruber/brace-expansion.svg)](https://greenkeeper.io/)
9 +
10 +[![testling badge](https://ci.testling.com/juliangruber/brace-expansion.png)](https://ci.testling.com/juliangruber/brace-expansion)
11 +
12 +## Example
13 +
14 +```js
15 +var expand = require('brace-expansion');
16 +
17 +expand('file-{a,b,c}.jpg')
18 +// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
19 +
20 +expand('-v{,,}')
21 +// => ['-v', '-v', '-v']
22 +
23 +expand('file{0..2}.jpg')
24 +// => ['file0.jpg', 'file1.jpg', 'file2.jpg']
25 +
26 +expand('file-{a..c}.jpg')
27 +// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
28 +
29 +expand('file{2..0}.jpg')
30 +// => ['file2.jpg', 'file1.jpg', 'file0.jpg']
31 +
32 +expand('file{0..4..2}.jpg')
33 +// => ['file0.jpg', 'file2.jpg', 'file4.jpg']
34 +
35 +expand('file-{a..e..2}.jpg')
36 +// => ['file-a.jpg', 'file-c.jpg', 'file-e.jpg']
37 +
38 +expand('file{00..10..5}.jpg')
39 +// => ['file00.jpg', 'file05.jpg', 'file10.jpg']
40 +
41 +expand('{{A..C},{a..c}}')
42 +// => ['A', 'B', 'C', 'a', 'b', 'c']
43 +
44 +expand('ppp{,config,oe{,conf}}')
45 +// => ['ppp', 'pppconfig', 'pppoe', 'pppoeconf']
46 +```
47 +
48 +## API
49 +
50 +```js
51 +var expand = require('brace-expansion');
52 +```
53 +
54 +### var expanded = expand(str)
55 +
56 +Return an array of all possible and valid expansions of `str`. If none are
57 +found, `[str]` is returned.
58 +
59 +Valid expansions are:
60 +
61 +```js
62 +/^(.*,)+(.+)?$/
63 +// {a,b,...}
64 +```
65 +
66 +A comma separated list of options, like `{a,b}` or `{a,{b,c}}` or `{,a,}`.
67 +
68 +```js
69 +/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
70 +// {x..y[..incr]}
71 +```
72 +
73 +A numeric sequence from `x` to `y` inclusive, with optional increment.
74 +If `x` or `y` start with a leading `0`, all the numbers will be padded
75 +to have equal length. Negative numbers and backwards iteration work too.
76 +
77 +```js
78 +/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
79 +// {x..y[..incr]}
80 +```
81 +
82 +An alphabetic sequence from `x` to `y` inclusive, with optional increment.
83 +`x` and `y` must be exactly one character, and if given, `incr` must be a
84 +number.
85 +
86 +For compatibility reasons, the string `${` is not eligible for brace expansion.
87 +
88 +## Installation
89 +
90 +With [npm](https://npmjs.org) do:
91 +
92 +```bash
93 +npm install brace-expansion
94 +```
95 +
96 +## Contributors
97 +
98 +- [Julian Gruber](https://github.com/juliangruber)
99 +- [Isaac Z. Schlueter](https://github.com/isaacs)
100 +
101 +## Sponsors
102 +
103 +This module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)!
104 +
105 +Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)!
106 +
107 +## License
108 +
109 +(MIT)
110 +
111 +Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
112 +
113 +Permission is hereby granted, free of charge, to any person obtaining a copy of
114 +this software and associated documentation files (the "Software"), to deal in
115 +the Software without restriction, including without limitation the rights to
116 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
117 +of the Software, and to permit persons to whom the Software is furnished to do
118 +so, subject to the following conditions:
119 +
120 +The above copyright notice and this permission notice shall be included in all
121 +copies or substantial portions of the Software.
122 +
123 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
124 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
125 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
126 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
127 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
128 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
129 +SOFTWARE.
1 +var concatMap = require('concat-map');
2 +var balanced = require('balanced-match');
3 +
4 +module.exports = expandTop;
5 +
6 +var escSlash = '\0SLASH'+Math.random()+'\0';
7 +var escOpen = '\0OPEN'+Math.random()+'\0';
8 +var escClose = '\0CLOSE'+Math.random()+'\0';
9 +var escComma = '\0COMMA'+Math.random()+'\0';
10 +var escPeriod = '\0PERIOD'+Math.random()+'\0';
11 +
12 +function numeric(str) {
13 + return parseInt(str, 10) == str
14 + ? parseInt(str, 10)
15 + : str.charCodeAt(0);
16 +}
17 +
18 +function escapeBraces(str) {
19 + return str.split('\\\\').join(escSlash)
20 + .split('\\{').join(escOpen)
21 + .split('\\}').join(escClose)
22 + .split('\\,').join(escComma)
23 + .split('\\.').join(escPeriod);
24 +}
25 +
26 +function unescapeBraces(str) {
27 + return str.split(escSlash).join('\\')
28 + .split(escOpen).join('{')
29 + .split(escClose).join('}')
30 + .split(escComma).join(',')
31 + .split(escPeriod).join('.');
32 +}
33 +
34 +
35 +// Basically just str.split(","), but handling cases
36 +// where we have nested braced sections, which should be
37 +// treated as individual members, like {a,{b,c},d}
38 +function parseCommaParts(str) {
39 + if (!str)
40 + return [''];
41 +
42 + var parts = [];
43 + var m = balanced('{', '}', str);
44 +
45 + if (!m)
46 + return str.split(',');
47 +
48 + var pre = m.pre;
49 + var body = m.body;
50 + var post = m.post;
51 + var p = pre.split(',');
52 +
53 + p[p.length-1] += '{' + body + '}';
54 + var postParts = parseCommaParts(post);
55 + if (post.length) {
56 + p[p.length-1] += postParts.shift();
57 + p.push.apply(p, postParts);
58 + }
59 +
60 + parts.push.apply(parts, p);
61 +
62 + return parts;
63 +}
64 +
65 +function expandTop(str) {
66 + if (!str)
67 + return [];
68 +
69 + // I don't know why Bash 4.3 does this, but it does.
70 + // Anything starting with {} will have the first two bytes preserved
71 + // but *only* at the top level, so {},a}b will not expand to anything,
72 + // but a{},b}c will be expanded to [a}c,abc].
73 + // One could argue that this is a bug in Bash, but since the goal of
74 + // this module is to match Bash's rules, we escape a leading {}
75 + if (str.substr(0, 2) === '{}') {
76 + str = '\\{\\}' + str.substr(2);
77 + }
78 +
79 + return expand(escapeBraces(str), true).map(unescapeBraces);
80 +}
81 +
82 +function identity(e) {
83 + return e;
84 +}
85 +
86 +function embrace(str) {
87 + return '{' + str + '}';
88 +}
89 +function isPadded(el) {
90 + return /^-?0\d/.test(el);
91 +}
92 +
93 +function lte(i, y) {
94 + return i <= y;
95 +}
96 +function gte(i, y) {
97 + return i >= y;
98 +}
99 +
100 +function expand(str, isTop) {
101 + var expansions = [];
102 +
103 + var m = balanced('{', '}', str);
104 + if (!m || /\$$/.test(m.pre)) return [str];
105 +
106 + var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
107 + var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
108 + var isSequence = isNumericSequence || isAlphaSequence;
109 + var isOptions = m.body.indexOf(',') >= 0;
110 + if (!isSequence && !isOptions) {
111 + // {a},b}
112 + if (m.post.match(/,.*\}/)) {
113 + str = m.pre + '{' + m.body + escClose + m.post;
114 + return expand(str);
115 + }
116 + return [str];
117 + }
118 +
119 + var n;
120 + if (isSequence) {
121 + n = m.body.split(/\.\./);
122 + } else {
123 + n = parseCommaParts(m.body);
124 + if (n.length === 1) {
125 + // x{{a,b}}y ==> x{a}y x{b}y
126 + n = expand(n[0], false).map(embrace);
127 + if (n.length === 1) {
128 + var post = m.post.length
129 + ? expand(m.post, false)
130 + : [''];
131 + return post.map(function(p) {
132 + return m.pre + n[0] + p;
133 + });
134 + }
135 + }
136 + }
137 +
138 + // at this point, n is the parts, and we know it's not a comma set
139 + // with a single entry.
140 +
141 + // no need to expand pre, since it is guaranteed to be free of brace-sets
142 + var pre = m.pre;
143 + var post = m.post.length
144 + ? expand(m.post, false)
145 + : [''];
146 +
147 + var N;
148 +
149 + if (isSequence) {
150 + var x = numeric(n[0]);
151 + var y = numeric(n[1]);
152 + var width = Math.max(n[0].length, n[1].length)
153 + var incr = n.length == 3
154 + ? Math.abs(numeric(n[2]))
155 + : 1;
156 + var test = lte;
157 + var reverse = y < x;
158 + if (reverse) {
159 + incr *= -1;
160 + test = gte;
161 + }
162 + var pad = n.some(isPadded);
163 +
164 + N = [];
165 +
166 + for (var i = x; test(i, y); i += incr) {
167 + var c;
168 + if (isAlphaSequence) {
169 + c = String.fromCharCode(i);
170 + if (c === '\\')
171 + c = '';
172 + } else {
173 + c = String(i);
174 + if (pad) {
175 + var need = width - c.length;
176 + if (need > 0) {
177 + var z = new Array(need + 1).join('0');
178 + if (i < 0)
179 + c = '-' + z + c.slice(1);
180 + else
181 + c = z + c;
182 + }
183 + }
184 + }
185 + N.push(c);
186 + }
187 + } else {
188 + N = concatMap(n, function(el) { return expand(el, false) });
189 + }
190 +
191 + for (var j = 0; j < N.length; j++) {
192 + for (var k = 0; k < post.length; k++) {
193 + var expansion = pre + N[j] + post[k];
194 + if (!isTop || isSequence || expansion)
195 + expansions.push(expansion);
196 + }
197 + }
198 +
199 + return expansions;
200 +}
201 +
1 +{
2 + "_from": "brace-expansion@^1.1.7",
3 + "_id": "brace-expansion@1.1.11",
4 + "_inBundle": false,
5 + "_integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
6 + "_location": "/brace-expansion",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "brace-expansion@^1.1.7",
12 + "name": "brace-expansion",
13 + "escapedName": "brace-expansion",
14 + "rawSpec": "^1.1.7",
15 + "saveSpec": null,
16 + "fetchSpec": "^1.1.7"
17 + },
18 + "_requiredBy": [
19 + "/minimatch"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
22 + "_shasum": "3c7fcbf529d87226f3d2f52b966ff5271eb441dd",
23 + "_spec": "brace-expansion@^1.1.7",
24 + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\minimatch",
25 + "author": {
26 + "name": "Julian Gruber",
27 + "email": "mail@juliangruber.com",
28 + "url": "http://juliangruber.com"
29 + },
30 + "bugs": {
31 + "url": "https://github.com/juliangruber/brace-expansion/issues"
32 + },
33 + "bundleDependencies": false,
34 + "dependencies": {
35 + "balanced-match": "^1.0.0",
36 + "concat-map": "0.0.1"
37 + },
38 + "deprecated": false,
39 + "description": "Brace expansion as known from sh/bash",
40 + "devDependencies": {
41 + "matcha": "^0.7.0",
42 + "tape": "^4.6.0"
43 + },
44 + "homepage": "https://github.com/juliangruber/brace-expansion",
45 + "keywords": [],
46 + "license": "MIT",
47 + "main": "index.js",
48 + "name": "brace-expansion",
49 + "repository": {
50 + "type": "git",
51 + "url": "git://github.com/juliangruber/brace-expansion.git"
52 + },
53 + "scripts": {
54 + "bench": "matcha test/perf/bench.js",
55 + "gentest": "bash test/generate.sh",
56 + "test": "tape test/*.js"
57 + },
58 + "testling": {
59 + "files": "test/*.js",
60 + "browsers": [
61 + "ie/8..latest",
62 + "firefox/20..latest",
63 + "firefox/nightly",
64 + "chrome/25..latest",
65 + "chrome/canary",
66 + "opera/12..latest",
67 + "opera/next",
68 + "safari/5.1..latest",
69 + "ipad/6.0..latest",
70 + "iphone/6.0..latest",
71 + "android-browser/4.2..latest"
72 + ]
73 + },
74 + "version": "1.1.11"
75 +}
1 +
2 +0.1.0 / 2012-07-04
3 +==================
4 +
5 + * add bytes to string conversion [yields]
1 +
2 +test:
3 + @./node_modules/.bin/mocha \
4 + --reporter spec \
5 + --require should
6 +
7 +.PHONY: test
...\ No newline at end of file ...\ No newline at end of file
1 +# node-bytes
2 +
3 + Byte string parser / formatter.
4 +
5 +## Example:
6 +
7 +```js
8 +bytes('1kb')
9 +// => 1024
10 +
11 +bytes('2mb')
12 +// => 2097152
13 +
14 +bytes('1gb')
15 +// => 1073741824
16 +
17 +bytes(1073741824)
18 +// => 1gb
19 +```
20 +
21 +## Installation
22 +
23 +```
24 +$ npm install bytes
25 +$ component install visionmedia/bytes.js
26 +```
27 +
28 +## License
29 +
30 +(The MIT License)
31 +
32 +Copyright (c) 2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
33 +
34 +Permission is hereby granted, free of charge, to any person obtaining
35 +a copy of this software and associated documentation files (the
36 +'Software'), to deal in the Software without restriction, including
37 +without limitation the rights to use, copy, modify, merge, publish,
38 +distribute, sublicense, and/or sell copies of the Software, and to
39 +permit persons to whom the Software is furnished to do so, subject to
40 +the following conditions:
41 +
42 +The above copyright notice and this permission notice shall be
43 +included in all copies or substantial portions of the Software.
44 +
45 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
46 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
48 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
49 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
50 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
51 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +{
2 + "name": "bytes",
3 + "description": "byte size string parser / serializer",
4 + "keywords": ["bytes", "utility"],
5 + "version": "0.1.0",
6 + "scripts": ["index.js"]
7 +}
1 +
2 +/**
3 + * Parse byte `size` string.
4 + *
5 + * @param {String} size
6 + * @return {Number}
7 + * @api public
8 + */
9 +
10 +module.exports = function(size) {
11 + if ('number' == typeof size) return convert(size);
12 + var parts = size.match(/^(\d+(?:\.\d+)?) *(kb|mb|gb)$/)
13 + , n = parseFloat(parts[1])
14 + , type = parts[2];
15 +
16 + var map = {
17 + kb: 1 << 10
18 + , mb: 1 << 20
19 + , gb: 1 << 30
20 + };
21 +
22 + return map[type] * n;
23 +};
24 +
25 +/**
26 + * convert bytes into string.
27 + *
28 + * @param {Number} b - bytes to convert
29 + * @return {String}i
30 + * @api public
31 + */
32 +
33 +function convert (b) {
34 + var gb = 1 << 30, mb = 1 << 20, kb = 1 << 10;
35 + if (b >= gb) return (Math.round(b / gb * 100) / 100) + 'gb';
36 + if (b >= mb) return (Math.round(b / mb * 100) / 100) + 'mb';
37 + if (b >= kb) return (Math.round(b / kb * 100) / 100) + 'kb';
38 + return b;
39 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "_from": "bytes@0.1.0",
3 + "_id": "bytes@0.1.0",
4 + "_inBundle": false,
5 + "_integrity": "sha1-xXSBIigSbWNp0VdpJahXnbP45aI=",
6 + "_location": "/bytes",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "version",
10 + "registry": true,
11 + "raw": "bytes@0.1.0",
12 + "name": "bytes",
13 + "escapedName": "bytes",
14 + "rawSpec": "0.1.0",
15 + "saveSpec": null,
16 + "fetchSpec": "0.1.0"
17 + },
18 + "_requiredBy": [
19 + "/connect"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/bytes/-/bytes-0.1.0.tgz",
22 + "_shasum": "c574812228126d6369d1576925a8579db3f8e5a2",
23 + "_spec": "bytes@0.1.0",
24 + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\connect",
25 + "author": {
26 + "name": "TJ Holowaychuk",
27 + "email": "tj@vision-media.ca",
28 + "url": "http://tjholowaychuk.com"
29 + },
30 + "bundleDependencies": false,
31 + "component": {
32 + "scripts": {
33 + "bytes": "index.js"
34 + }
35 + },
36 + "dependencies": {},
37 + "deprecated": false,
38 + "description": "byte size string parser / serializer",
39 + "devDependencies": {
40 + "mocha": "*",
41 + "should": "*"
42 + },
43 + "main": "index.js",
44 + "name": "bytes",
45 + "version": "0.1.0"
46 +}
1 +language: node_js
2 +node_js:
3 + - 0.4
4 + - 0.6
1 +
2 +0.6.1 / 2012-06-01
3 +==================
4 +
5 + * Added: append (yes or no) on confirmation
6 + * Added: allow node.js v0.7.x
7 +
8 +0.6.0 / 2012-04-10
9 +==================
10 +
11 + * Added `.prompt(obj, callback)` support. Closes #49
12 + * Added default support to .choose(). Closes #41
13 + * Fixed the choice example
14 +
15 +0.5.1 / 2011-12-20
16 +==================
17 +
18 + * Fixed `password()` for recent nodes. Closes #36
19 +
20 +0.5.0 / 2011-12-04
21 +==================
22 +
23 + * Added sub-command option support [itay]
24 +
25 +0.4.3 / 2011-12-04
26 +==================
27 +
28 + * Fixed custom help ordering. Closes #32
29 +
30 +0.4.2 / 2011-11-24
31 +==================
32 +
33 + * Added travis support
34 + * Fixed: line-buffered input automatically trimmed. Closes #31
35 +
36 +0.4.1 / 2011-11-18
37 +==================
38 +
39 + * Removed listening for "close" on --help
40 +
41 +0.4.0 / 2011-11-15
42 +==================
43 +
44 + * Added support for `--`. Closes #24
45 +
46 +0.3.3 / 2011-11-14
47 +==================
48 +
49 + * Fixed: wait for close event when writing help info [Jerry Hamlet]
50 +
51 +0.3.2 / 2011-11-01
52 +==================
53 +
54 + * Fixed long flag definitions with values [felixge]
55 +
56 +0.3.1 / 2011-10-31
57 +==================
58 +
59 + * Changed `--version` short flag to `-V` from `-v`
60 + * Changed `.version()` so it's configurable [felixge]
61 +
62 +0.3.0 / 2011-10-31
63 +==================
64 +
65 + * Added support for long flags only. Closes #18
66 +
67 +0.2.1 / 2011-10-24
68 +==================
69 +
70 + * "node": ">= 0.4.x < 0.7.0". Closes #20
71 +
72 +0.2.0 / 2011-09-26
73 +==================
74 +
75 + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
76 +
77 +0.1.0 / 2011-08-24
78 +==================
79 +
80 + * Added support for custom `--help` output
81 +
82 +0.0.5 / 2011-08-18
83 +==================
84 +
85 + * Changed: when the user enters nothing prompt for password again
86 + * Fixed issue with passwords beginning with numbers [NuckChorris]
87 +
88 +0.0.4 / 2011-08-15
89 +==================
90 +
91 + * Fixed `Commander#args`
92 +
93 +0.0.3 / 2011-08-15
94 +==================
95 +
96 + * Added default option value support
97 +
98 +0.0.2 / 2011-08-15
99 +==================
100 +
101 + * Added mask support to `Command#password(str[, mask], fn)`
102 + * Added `Command#password(str, fn)`
103 +
104 +0.0.1 / 2010-01-03
105 +==================
106 +
107 + * Initial release
1 +
2 +TESTS = $(shell find test/test.*.js)
3 +
4 +test:
5 + @./test/run $(TESTS)
6 +
7 +.PHONY: test
...\ No newline at end of file ...\ No newline at end of file
1 +# Commander.js
2 +
3 + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).
4 +
5 + [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)
6 +
7 +## Installation
8 +
9 + $ npm install commander
10 +
11 +## Option parsing
12 +
13 + Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.
14 +
15 +```js
16 +#!/usr/bin/env node
17 +
18 +/**
19 + * Module dependencies.
20 + */
21 +
22 +var program = require('commander');
23 +
24 +program
25 + .version('0.0.1')
26 + .option('-p, --peppers', 'Add peppers')
27 + .option('-P, --pineapple', 'Add pineapple')
28 + .option('-b, --bbq', 'Add bbq sauce')
29 + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
30 + .parse(process.argv);
31 +
32 +console.log('you ordered a pizza with:');
33 +if (program.peppers) console.log(' - peppers');
34 +if (program.pineapple) console.log(' - pineappe');
35 +if (program.bbq) console.log(' - bbq');
36 +console.log(' - %s cheese', program.cheese);
37 +```
38 +
39 + Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
40 +
41 +## Automated --help
42 +
43 + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
44 +
45 +```
46 + $ ./examples/pizza --help
47 +
48 + Usage: pizza [options]
49 +
50 + Options:
51 +
52 + -V, --version output the version number
53 + -p, --peppers Add peppers
54 + -P, --pineapple Add pineappe
55 + -b, --bbq Add bbq sauce
56 + -c, --cheese <type> Add the specified type of cheese [marble]
57 + -h, --help output usage information
58 +
59 +```
60 +
61 +## Coercion
62 +
63 +```js
64 +function range(val) {
65 + return val.split('..').map(Number);
66 +}
67 +
68 +function list(val) {
69 + return val.split(',');
70 +}
71 +
72 +program
73 + .version('0.0.1')
74 + .usage('[options] <file ...>')
75 + .option('-i, --integer <n>', 'An integer argument', parseInt)
76 + .option('-f, --float <n>', 'A float argument', parseFloat)
77 + .option('-r, --range <a>..<b>', 'A range', range)
78 + .option('-l, --list <items>', 'A list', list)
79 + .option('-o, --optional [value]', 'An optional value')
80 + .parse(process.argv);
81 +
82 +console.log(' int: %j', program.integer);
83 +console.log(' float: %j', program.float);
84 +console.log(' optional: %j', program.optional);
85 +program.range = program.range || [];
86 +console.log(' range: %j..%j', program.range[0], program.range[1]);
87 +console.log(' list: %j', program.list);
88 +console.log(' args: %j', program.args);
89 +```
90 +
91 +## Custom help
92 +
93 + You can display arbitrary `-h, --help` information
94 + by listening for "--help". Commander will automatically
95 + exit once you are done so that the remainder of your program
96 + does not execute causing undesired behaviours, for example
97 + in the following executable "stuff" will not output when
98 + `--help` is used.
99 +
100 +```js
101 +#!/usr/bin/env node
102 +
103 +/**
104 + * Module dependencies.
105 + */
106 +
107 +var program = require('../');
108 +
109 +function list(val) {
110 + return val.split(',').map(Number);
111 +}
112 +
113 +program
114 + .version('0.0.1')
115 + .option('-f, --foo', 'enable some foo')
116 + .option('-b, --bar', 'enable some bar')
117 + .option('-B, --baz', 'enable some baz');
118 +
119 +// must be before .parse() since
120 +// node's emit() is immediate
121 +
122 +program.on('--help', function(){
123 + console.log(' Examples:');
124 + console.log('');
125 + console.log(' $ custom-help --help');
126 + console.log(' $ custom-help -h');
127 + console.log('');
128 +});
129 +
130 +program.parse(process.argv);
131 +
132 +console.log('stuff');
133 +```
134 +
135 +yielding the following help output:
136 +
137 +```
138 +
139 +Usage: custom-help [options]
140 +
141 +Options:
142 +
143 + -h, --help output usage information
144 + -V, --version output the version number
145 + -f, --foo enable some foo
146 + -b, --bar enable some bar
147 + -B, --baz enable some baz
148 +
149 +Examples:
150 +
151 + $ custom-help --help
152 + $ custom-help -h
153 +
154 +```
155 +
156 +## .prompt(msg, fn)
157 +
158 + Single-line prompt:
159 +
160 +```js
161 +program.prompt('name: ', function(name){
162 + console.log('hi %s', name);
163 +});
164 +```
165 +
166 + Multi-line prompt:
167 +
168 +```js
169 +program.prompt('description:', function(name){
170 + console.log('hi %s', name);
171 +});
172 +```
173 +
174 + Coercion:
175 +
176 +```js
177 +program.prompt('Age: ', Number, function(age){
178 + console.log('age: %j', age);
179 +});
180 +```
181 +
182 +```js
183 +program.prompt('Birthdate: ', Date, function(date){
184 + console.log('date: %s', date);
185 +});
186 +```
187 +
188 +## .password(msg[, mask], fn)
189 +
190 +Prompt for password without echoing:
191 +
192 +```js
193 +program.password('Password: ', function(pass){
194 + console.log('got "%s"', pass);
195 + process.stdin.destroy();
196 +});
197 +```
198 +
199 +Prompt for password with mask char "*":
200 +
201 +```js
202 +program.password('Password: ', '*', function(pass){
203 + console.log('got "%s"', pass);
204 + process.stdin.destroy();
205 +});
206 +```
207 +
208 +## .confirm(msg, fn)
209 +
210 + Confirm with the given `msg`:
211 +
212 +```js
213 +program.confirm('continue? ', function(ok){
214 + console.log(' got %j', ok);
215 +});
216 +```
217 +
218 +## .choose(list, fn)
219 +
220 + Let the user choose from a `list`:
221 +
222 +```js
223 +var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];
224 +
225 +console.log('Choose the coolest pet:');
226 +program.choose(list, function(i){
227 + console.log('you chose %d "%s"', i, list[i]);
228 +});
229 +```
230 +
231 +## Links
232 +
233 + - [API documentation](http://visionmedia.github.com/commander.js/)
234 + - [ascii tables](https://github.com/LearnBoost/cli-table)
235 + - [progress bars](https://github.com/visionmedia/node-progress)
236 + - [more progress bars](https://github.com/substack/node-multimeter)
237 + - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)
238 +
239 +## License
240 +
241 +(The MIT License)
242 +
243 +Copyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
244 +
245 +Permission is hereby granted, free of charge, to any person obtaining
246 +a copy of this software and associated documentation files (the
247 +'Software'), to deal in the Software without restriction, including
248 +without limitation the rights to use, copy, modify, merge, publish,
249 +distribute, sublicense, and/or sell copies of the Software, and to
250 +permit persons to whom the Software is furnished to do so, subject to
251 +the following conditions:
252 +
253 +The above copyright notice and this permission notice shall be
254 +included in all copies or substantial portions of the Software.
255 +
256 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
257 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
259 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
260 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
261 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
262 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +module.exports = require('./lib/commander');
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
1 +{
2 + "_from": "commander@0.6.1",
3 + "_id": "commander@0.6.1",
4 + "_inBundle": false,
5 + "_integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=",
6 + "_location": "/commander",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "version",
10 + "registry": true,
11 + "raw": "commander@0.6.1",
12 + "name": "commander",
13 + "escapedName": "commander",
14 + "rawSpec": "0.6.1",
15 + "saveSpec": null,
16 + "fetchSpec": "0.6.1"
17 + },
18 + "_requiredBy": [
19 + "/express"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz",
22 + "_shasum": "fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06",
23 + "_spec": "commander@0.6.1",
24 + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\express",
25 + "author": {
26 + "name": "TJ Holowaychuk",
27 + "email": "tj@vision-media.ca"
28 + },
29 + "bugs": {
30 + "url": "https://github.com/visionmedia/commander.js/issues"
31 + },
32 + "bundleDependencies": false,
33 + "dependencies": {},
34 + "deprecated": false,
35 + "description": "the complete solution for node.js command-line programs",
36 + "devDependencies": {
37 + "should": ">= 0.0.1"
38 + },
39 + "engines": {
40 + "node": ">= 0.4.x"
41 + },
42 + "homepage": "https://github.com/visionmedia/commander.js#readme",
43 + "keywords": [
44 + "command",
45 + "option",
46 + "parser",
47 + "prompt",
48 + "stdin"
49 + ],
50 + "main": "index",
51 + "name": "commander",
52 + "repository": {
53 + "type": "git",
54 + "url": "git+https://github.com/visionmedia/commander.js.git"
55 + },
56 + "scripts": {
57 + "test": "make test"
58 + },
59 + "version": "0.6.1"
60 +}
1 +language: node_js
2 +node_js:
3 + - 0.4
4 + - 0.6
1 +This software is released under the MIT license:
2 +
3 +Permission is hereby granted, free of charge, to any person obtaining a copy of
4 +this software and associated documentation files (the "Software"), to deal in
5 +the Software without restriction, including without limitation the rights to
6 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 +the Software, and to permit persons to whom the Software is furnished to do so,
8 +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, FITNESS
15 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +concat-map
2 +==========
3 +
4 +Concatenative mapdashery.
5 +
6 +[![browser support](http://ci.testling.com/substack/node-concat-map.png)](http://ci.testling.com/substack/node-concat-map)
7 +
8 +[![build status](https://secure.travis-ci.org/substack/node-concat-map.png)](http://travis-ci.org/substack/node-concat-map)
9 +
10 +example
11 +=======
12 +
13 +``` js
14 +var concatMap = require('concat-map');
15 +var xs = [ 1, 2, 3, 4, 5, 6 ];
16 +var ys = concatMap(xs, function (x) {
17 + return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
18 +});
19 +console.dir(ys);
20 +```
21 +
22 +***
23 +
24 +```
25 +[ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]
26 +```
27 +
28 +methods
29 +=======
30 +
31 +``` js
32 +var concatMap = require('concat-map')
33 +```
34 +
35 +concatMap(xs, fn)
36 +-----------------
37 +
38 +Return an array of concatenated elements by calling `fn(x, i)` for each element
39 +`x` and each index `i` in the array `xs`.
40 +
41 +When `fn(x, i)` returns an array, its result will be concatenated with the
42 +result array. If `fn(x, i)` returns anything else, that value will be pushed
43 +onto the end of the result array.
44 +
45 +install
46 +=======
47 +
48 +With [npm](http://npmjs.org) do:
49 +
50 +```
51 +npm install concat-map
52 +```
53 +
54 +license
55 +=======
56 +
57 +MIT
58 +
59 +notes
60 +=====
61 +
62 +This module was written while sitting high above the ground in a tree.
1 +var concatMap = require('../');
2 +var xs = [ 1, 2, 3, 4, 5, 6 ];
3 +var ys = concatMap(xs, function (x) {
4 + return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
5 +});
6 +console.dir(ys);
1 +module.exports = function (xs, fn) {
2 + var res = [];
3 + for (var i = 0; i < xs.length; i++) {
4 + var x = fn(xs[i], i);
5 + if (isArray(x)) res.push.apply(res, x);
6 + else res.push(x);
7 + }
8 + return res;
9 +};
10 +
11 +var isArray = Array.isArray || function (xs) {
12 + return Object.prototype.toString.call(xs) === '[object Array]';
13 +};
1 +{
2 + "_from": "concat-map@0.0.1",
3 + "_id": "concat-map@0.0.1",
4 + "_inBundle": false,
5 + "_integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
6 + "_location": "/concat-map",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "version",
10 + "registry": true,
11 + "raw": "concat-map@0.0.1",
12 + "name": "concat-map",
13 + "escapedName": "concat-map",
14 + "rawSpec": "0.0.1",
15 + "saveSpec": null,
16 + "fetchSpec": "0.0.1"
17 + },
18 + "_requiredBy": [
19 + "/brace-expansion"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
22 + "_shasum": "d8a96bd77fd68df7793a73036a3ba0d5405d477b",
23 + "_spec": "concat-map@0.0.1",
24 + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\brace-expansion",
25 + "author": {
26 + "name": "James Halliday",
27 + "email": "mail@substack.net",
28 + "url": "http://substack.net"
29 + },
30 + "bugs": {
31 + "url": "https://github.com/substack/node-concat-map/issues"
32 + },
33 + "bundleDependencies": false,
34 + "deprecated": false,
35 + "description": "concatenative mapdashery",
36 + "devDependencies": {
37 + "tape": "~2.4.0"
38 + },
39 + "directories": {
40 + "example": "example",
41 + "test": "test"
42 + },
43 + "homepage": "https://github.com/substack/node-concat-map#readme",
44 + "keywords": [
45 + "concat",
46 + "concatMap",
47 + "map",
48 + "functional",
49 + "higher-order"
50 + ],
51 + "license": "MIT",
52 + "main": "index.js",
53 + "name": "concat-map",
54 + "repository": {
55 + "type": "git",
56 + "url": "git://github.com/substack/node-concat-map.git"
57 + },
58 + "scripts": {
59 + "test": "tape test/*.js"
60 + },
61 + "testling": {
62 + "files": "test/*.js",
63 + "browsers": {
64 + "ie": [
65 + 6,
66 + 7,
67 + 8,
68 + 9
69 + ],
70 + "ff": [
71 + 3.5,
72 + 10,
73 + 15
74 + ],
75 + "chrome": [
76 + 10,
77 + 22
78 + ],
79 + "safari": [
80 + 5.1
81 + ],
82 + "opera": [
83 + 12
84 + ]
85 + }
86 + },
87 + "version": "0.0.1"
88 +}
1 +var concatMap = require('../');
2 +var test = require('tape');
3 +
4 +test('empty or not', function (t) {
5 + var xs = [ 1, 2, 3, 4, 5, 6 ];
6 + var ixes = [];
7 + var ys = concatMap(xs, function (x, ix) {
8 + ixes.push(ix);
9 + return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
10 + });
11 + t.same(ys, [ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]);
12 + t.same(ixes, [ 0, 1, 2, 3, 4, 5 ]);
13 + t.end();
14 +});
15 +
16 +test('always something', function (t) {
17 + var xs = [ 'a', 'b', 'c', 'd' ];
18 + var ys = concatMap(xs, function (x) {
19 + return x === 'b' ? [ 'B', 'B', 'B' ] : [ x ];
20 + });
21 + t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]);
22 + t.end();
23 +});
24 +
25 +test('scalars', function (t) {
26 + var xs = [ 'a', 'b', 'c', 'd' ];
27 + var ys = concatMap(xs, function (x) {
28 + return x === 'b' ? [ 'B', 'B', 'B' ] : x;
29 + });
30 + t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]);
31 + t.end();
32 +});
33 +
34 +test('undefs', function (t) {
35 + var xs = [ 'a', 'b', 'c', 'd' ];
36 + var ys = concatMap(xs, function () {});
37 + t.same(ys, [ undefined, undefined, undefined, undefined ]);
38 + t.end();
39 +});
1 +*.markdown
2 +*.md
3 +.git*
4 +Makefile
5 +benchmarks/
6 +docs/
7 +examples/
8 +install.sh
9 +support/
10 +test/
11 +.DS_Store
12 +coverage.html
1 +language: node_js
2 +node_js:
3 + - 0.6
4 + - 0.8
...\ No newline at end of file ...\ No newline at end of file
1 +(The MIT License)
2 +
3 +Copyright (c) 2010 Sencha Inc.
4 +Copyright (c) 2011 LearnBoost
5 +Copyright (c) 2011 TJ Holowaychuk
6 +
7 +Permission is hereby granted, free of charge, to any person obtaining
8 +a copy of this software and associated documentation files (the
9 +'Software'), to deal in the Software without restriction, including
10 +without limitation the rights to use, copy, modify, merge, publish,
11 +distribute, sublicense, and/or sell copies of the Software, and to
12 +permit persons to whom the Software is furnished to do so, subject to
13 +the following conditions:
14 +
15 +The above copyright notice and this permission notice shall be
16 +included in all copies or substantial portions of the Software.
17 +
18 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
19 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
...\ No newline at end of file ...\ No newline at end of file
1 +[![build status](https://secure.travis-ci.org/senchalabs/connect.png)](http://travis-ci.org/senchalabs/connect)
2 +# Connect
3 +
4 + Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance "plugins" known as _middleware_.
5 +
6 + Connect is bundled with over _20_ commonly used middleware, including
7 + a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://senchalabs.github.com/connect/).
8 +
9 +```js
10 +var connect = require('connect')
11 + , http = require('http');
12 +
13 +var app = connect()
14 + .use(connect.favicon())
15 + .use(connect.logger('dev'))
16 + .use(connect.static('public'))
17 + .use(connect.directory('public'))
18 + .use(connect.cookieParser())
19 + .use(connect.session({ secret: 'my secret here' }))
20 + .use(function(req, res){
21 + res.end('Hello from Connect!\n');
22 + });
23 +
24 +http.createServer(app).listen(3000);
25 +```
26 +
27 +## Middleware
28 +
29 + - [csrf](http://www.senchalabs.org/connect/csrf.html)
30 + - [basicAuth](http://www.senchalabs.org/connect/basicAuth.html)
31 + - [bodyParser](http://www.senchalabs.org/connect/bodyParser.html)
32 + - [json](http://www.senchalabs.org/connect/json.html)
33 + - [multipart](http://www.senchalabs.org/connect/multipart.html)
34 + - [urlencoded](http://www.senchalabs.org/connect/urlencoded.html)
35 + - [cookieParser](http://www.senchalabs.org/connect/cookieParser.html)
36 + - [directory](http://www.senchalabs.org/connect/directory.html)
37 + - [compress](http://www.senchalabs.org/connect/compress.html)
38 + - [errorHandler](http://www.senchalabs.org/connect/errorHandler.html)
39 + - [favicon](http://www.senchalabs.org/connect/favicon.html)
40 + - [limit](http://www.senchalabs.org/connect/limit.html)
41 + - [logger](http://www.senchalabs.org/connect/logger.html)
42 + - [methodOverride](http://www.senchalabs.org/connect/methodOverride.html)
43 + - [query](http://www.senchalabs.org/connect/query.html)
44 + - [responseTime](http://www.senchalabs.org/connect/responseTime.html)
45 + - [session](http://www.senchalabs.org/connect/session.html)
46 + - [static](http://www.senchalabs.org/connect/static.html)
47 + - [staticCache](http://www.senchalabs.org/connect/staticCache.html)
48 + - [vhost](http://www.senchalabs.org/connect/vhost.html)
49 + - [subdomains](http://www.senchalabs.org/connect/subdomains.html)
50 + - [cookieSession](http://www.senchalabs.org/connect/cookieSession.html)
51 +
52 +## Running Tests
53 +
54 +first:
55 +
56 + $ npm install -d
57 +
58 +then:
59 +
60 + $ make test
61 +
62 +## Authors
63 +
64 + Below is the output from [git-summary](http://github.com/visionmedia/git-extras).
65 +
66 +
67 + project: connect
68 + commits: 2033
69 + active : 301 days
70 + files : 171
71 + authors:
72 + 1414 Tj Holowaychuk 69.6%
73 + 298 visionmedia 14.7%
74 + 191 Tim Caswell 9.4%
75 + 51 TJ Holowaychuk 2.5%
76 + 10 Ryan Olds 0.5%
77 + 8 Astro 0.4%
78 + 5 Nathan Rajlich 0.2%
79 + 5 Jakub Nešetřil 0.2%
80 + 3 Daniel Dickison 0.1%
81 + 3 David Rio Deiros 0.1%
82 + 3 Alexander Simmerl 0.1%
83 + 3 Andreas Lind Petersen 0.1%
84 + 2 Aaron Heckmann 0.1%
85 + 2 Jacques Crocker 0.1%
86 + 2 Fabian Jakobs 0.1%
87 + 2 Brian J Brennan 0.1%
88 + 2 Adam Malcontenti-Wilson 0.1%
89 + 2 Glen Mailer 0.1%
90 + 2 James Campos 0.1%
91 + 1 Trent Mick 0.0%
92 + 1 Troy Kruthoff 0.0%
93 + 1 Wei Zhu 0.0%
94 + 1 comerc 0.0%
95 + 1 darobin 0.0%
96 + 1 nateps 0.0%
97 + 1 Marco Sanson 0.0%
98 + 1 Arthur Taylor 0.0%
99 + 1 Aseem Kishore 0.0%
100 + 1 Bart Teeuwisse 0.0%
101 + 1 Cameron Howey 0.0%
102 + 1 Chad Weider 0.0%
103 + 1 Craig Barnes 0.0%
104 + 1 Eran Hammer-Lahav 0.0%
105 + 1 Gregory McWhirter 0.0%
106 + 1 Guillermo Rauch 0.0%
107 + 1 Jae Kwon 0.0%
108 + 1 Jakub Nesetril 0.0%
109 + 1 Joshua Peek 0.0%
110 + 1 Jxck 0.0%
111 + 1 AJ ONeal 0.0%
112 + 1 Michael Hemesath 0.0%
113 + 1 Morten Siebuhr 0.0%
114 + 1 Samori Gorse 0.0%
115 + 1 Tom Jensen 0.0%
116 +
117 +## Node Compatibility
118 +
119 + Connect `< 1.x` is compatible with node 0.2.x
120 +
121 +
122 + Connect `1.x` is compatible with node 0.4.x
123 +
124 +
125 + Connect (_master_) `2.x` is compatible with node 0.6.x
126 +
127 +## CLA
128 +
129 + [http://sencha.com/cla](http://sencha.com/cla)
130 +
131 +## License
132 +
133 +View the [LICENSE](https://github.com/senchalabs/connect/blob/master/LICENSE) file. The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons used by the `directory` middleware created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/).
1 +
2 +module.exports = process.env.CONNECT_COV
3 + ? require('./lib-cov/connect')
4 + : require('./lib/connect');
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +/*!
3 + * Connect - Cache
4 + * Copyright(c) 2011 Sencha Inc.
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Expose `Cache`.
10 + */
11 +
12 +module.exports = Cache;
13 +
14 +/**
15 + * LRU cache store.
16 + *
17 + * @param {Number} limit
18 + * @api private
19 + */
20 +
21 +function Cache(limit) {
22 + this.store = {};
23 + this.keys = [];
24 + this.limit = limit;
25 +}
26 +
27 +/**
28 + * Touch `key`, promoting the object.
29 + *
30 + * @param {String} key
31 + * @param {Number} i
32 + * @api private
33 + */
34 +
35 +Cache.prototype.touch = function(key, i){
36 + this.keys.splice(i,1);
37 + this.keys.push(key);
38 +};
39 +
40 +/**
41 + * Remove `key`.
42 + *
43 + * @param {String} key
44 + * @api private
45 + */
46 +
47 +Cache.prototype.remove = function(key){
48 + delete this.store[key];
49 +};
50 +
51 +/**
52 + * Get the object stored for `key`.
53 + *
54 + * @param {String} key
55 + * @return {Array}
56 + * @api private
57 + */
58 +
59 +Cache.prototype.get = function(key){
60 + return this.store[key];
61 +};
62 +
63 +/**
64 + * Add a cache `key`.
65 + *
66 + * @param {String} key
67 + * @return {Array}
68 + * @api private
69 + */
70 +
71 +Cache.prototype.add = function(key){
72 + // initialize store
73 + var len = this.keys.push(key);
74 +
75 + // limit reached, invalidate LRU
76 + if (len > this.limit) this.remove(this.keys.shift());
77 +
78 + var arr = this.store[key] = [];
79 + arr.createdAt = new Date;
80 + return arr;
81 +};
1 +
2 +/*!
3 + * Connect
4 + * Copyright(c) 2010 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var EventEmitter = require('events').EventEmitter
14 + , proto = require('./proto')
15 + , utils = require('./utils')
16 + , path = require('path')
17 + , basename = path.basename
18 + , fs = require('fs');
19 +
20 +// node patches
21 +
22 +require('./patch');
23 +
24 +// expose createServer() as the module
25 +
26 +exports = module.exports = createServer;
27 +
28 +/**
29 + * Framework version.
30 + */
31 +
32 +exports.version = '2.6.1';
33 +
34 +/**
35 + * Expose mime module.
36 + */
37 +
38 +exports.mime = require('./middleware/static').mime;
39 +
40 +/**
41 + * Expose the prototype.
42 + */
43 +
44 +exports.proto = proto;
45 +
46 +/**
47 + * Auto-load middleware getters.
48 + */
49 +
50 +exports.middleware = {};
51 +
52 +/**
53 + * Expose utilities.
54 + */
55 +
56 +exports.utils = utils;
57 +
58 +/**
59 + * Create a new connect server.
60 + *
61 + * @return {Function}
62 + * @api public
63 + */
64 +
65 +function createServer() {
66 + function app(req, res){ app.handle(req, res); }
67 + utils.merge(app, proto);
68 + utils.merge(app, EventEmitter.prototype);
69 + app.route = '/';
70 + app.stack = [];
71 + for (var i = 0; i < arguments.length; ++i) {
72 + app.use(arguments[i]);
73 + }
74 + return app;
75 +};
76 +
77 +/**
78 + * Support old `.createServer()` method.
79 + */
80 +
81 +createServer.createServer = createServer;
82 +
83 +/**
84 + * Auto-load bundled middleware with getters.
85 + */
86 +
87 +fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
88 + if (!/\.js$/.test(filename)) return;
89 + var name = basename(filename, '.js');
90 + function load(){ return require('./middleware/' + name); }
91 + exports.middleware.__defineGetter__(name, load);
92 + exports.__defineGetter__(name, load);
93 +});
1 +
2 +/**
3 + * Connect is a middleware framework for node,
4 + * shipping with over 18 bundled middleware and a rich selection of
5 + * 3rd-party middleware.
6 + *
7 + * var app = connect()
8 + * .use(connect.logger('dev'))
9 + * .use(connect.static('public'))
10 + * .use(function(req, res){
11 + * res.end('hello world\n');
12 + * })
13 + * .listen(3000);
14 + *
15 + * Installation:
16 + *
17 + * $ npm install connect
18 + *
19 + * Middleware:
20 + *
21 + * - [logger](logger.html) request logger with custom format support
22 + * - [csrf](csrf.html) Cross-site request forgery protection
23 + * - [compress](compress.html) Gzip compression middleware
24 + * - [basicAuth](basicAuth.html) basic http authentication
25 + * - [bodyParser](bodyParser.html) extensible request body parser
26 + * - [json](json.html) application/json parser
27 + * - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser
28 + * - [multipart](multipart.html) multipart/form-data parser
29 + * - [timeout](timeout.html) request timeouts
30 + * - [cookieParser](cookieParser.html) cookie parser
31 + * - [session](session.html) session management support with bundled MemoryStore
32 + * - [cookieSession](cookieSession.html) cookie-based session support
33 + * - [methodOverride](methodOverride.html) faux HTTP method support
34 + * - [responseTime](responseTime.html) calculates response-time and exposes via X-Response-Time
35 + * - [staticCache](staticCache.html) memory cache layer for the static() middleware
36 + * - [static](static.html) streaming static file server supporting `Range` and more
37 + * - [directory](directory.html) directory listing middleware
38 + * - [vhost](vhost.html) virtual host sub-domain mapping middleware
39 + * - [favicon](favicon.html) efficient favicon server (with default icon)
40 + * - [limit](limit.html) limit the bytesize of request bodies
41 + * - [query](query.html) automatic querystring parser, populating `req.query`
42 + * - [errorHandler](errorHandler.html) flexible error handler
43 + *
44 + * Links:
45 + *
46 + * - list of [3rd-party](https://github.com/senchalabs/connect/wiki) middleware
47 + * - GitHub [repository](http://github.com/senchalabs/connect)
48 + * - [test documentation](https://github.com/senchalabs/connect/blob/gh-pages/tests.md)
49 + *
50 + */
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +/*!
3 + * Connect - basicAuth
4 + * Copyright(c) 2010 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var utils = require('../utils')
14 + , unauthorized = utils.unauthorized;
15 +
16 +/**
17 + * Basic Auth:
18 + *
19 + * Enfore basic authentication by providing a `callback(user, pass)`,
20 + * which must return `true` in order to gain access. Alternatively an async
21 + * method is provided as well, invoking `callback(user, pass, callback)`. Populates
22 + * `req.user`. The final alternative is simply passing username / password
23 + * strings.
24 + *
25 + * Simple username and password
26 + *
27 + * connect(connect.basicAuth('username', 'password'));
28 + *
29 + * Callback verification
30 + *
31 + * connect()
32 + * .use(connect.basicAuth(function(user, pass){
33 + * return 'tj' == user & 'wahoo' == pass;
34 + * }))
35 + *
36 + * Async callback verification, accepting `fn(err, user)`.
37 + *
38 + * connect()
39 + * .use(connect.basicAuth(function(user, pass, fn){
40 + * User.authenticate({ user: user, pass: pass }, fn);
41 + * }))
42 + *
43 + * @param {Function|String} callback or username
44 + * @param {String} realm
45 + * @api public
46 + */
47 +
48 +module.exports = function basicAuth(callback, realm) {
49 + var username, password;
50 +
51 + // user / pass strings
52 + if ('string' == typeof callback) {
53 + username = callback;
54 + password = realm;
55 + if ('string' != typeof password) throw new Error('password argument required');
56 + realm = arguments[2];
57 + callback = function(user, pass){
58 + return user == username && pass == password;
59 + }
60 + }
61 +
62 + realm = realm || 'Authorization Required';
63 +
64 + return function(req, res, next) {
65 + var authorization = req.headers.authorization;
66 +
67 + if (req.user) return next();
68 + if (!authorization) return unauthorized(res, realm);
69 +
70 + var parts = authorization.split(' ')
71 +
72 + if (parts.length !== 2) return next(utils.error(400));
73 +
74 + var scheme = parts[0]
75 + , credentials = new Buffer(parts[1], 'base64').toString().split(':')
76 + , user = credentials[0]
77 + , pass = credentials[1];
78 +
79 + if ('Basic' != scheme) return next(utils.error(400));
80 +
81 + // async
82 + if (callback.length >= 3) {
83 + var pause = utils.pause(req);
84 + callback(user, pass, function(err, user){
85 + if (err || !user) return unauthorized(res, realm);
86 + req.user = req.remoteUser = user;
87 + next();
88 + pause.resume();
89 + });
90 + // sync
91 + } else {
92 + if (callback(user, pass)) {
93 + req.user = req.remoteUser = user;
94 + next();
95 + } else {
96 + unauthorized(res, realm);
97 + }
98 + }
99 + }
100 +};
101 +
1 +
2 +/*!
3 + * Connect - bodyParser
4 + * Copyright(c) 2010 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var multipart = require('./multipart')
14 + , urlencoded = require('./urlencoded')
15 + , json = require('./json');
16 +
17 +/**
18 + * Body parser:
19 + *
20 + * Parse request bodies, supports _application/json_,
21 + * _application/x-www-form-urlencoded_, and _multipart/form-data_.
22 + *
23 + * This is equivalent to:
24 + *
25 + * app.use(connect.json());
26 + * app.use(connect.urlencoded());
27 + * app.use(connect.multipart());
28 + *
29 + * Examples:
30 + *
31 + * connect()
32 + * .use(connect.bodyParser())
33 + * .use(function(req, res) {
34 + * res.end('viewing user ' + req.body.user.name);
35 + * });
36 + *
37 + * $ curl -d 'user[name]=tj' http://local/
38 + * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/
39 + *
40 + * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info.
41 + *
42 + * @param {Object} options
43 + * @return {Function}
44 + * @api public
45 + */
46 +
47 +exports = module.exports = function bodyParser(options){
48 + var _urlencoded = urlencoded(options)
49 + , _multipart = multipart(options)
50 + , _json = json(options);
51 +
52 + return function bodyParser(req, res, next) {
53 + _json(req, res, function(err){
54 + if (err) return next(err);
55 + _urlencoded(req, res, function(err){
56 + if (err) return next(err);
57 + _multipart(req, res, next);
58 + });
59 + });
60 + }
61 +};
...\ No newline at end of file ...\ No newline at end of file
1 +/*!
2 + * Connect - compress
3 + * Copyright(c) 2010 Sencha Inc.
4 + * Copyright(c) 2011 TJ Holowaychuk
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Module dependencies.
10 + */
11 +
12 +var zlib = require('zlib');
13 +
14 +/**
15 + * Supported content-encoding methods.
16 + */
17 +
18 +exports.methods = {
19 + gzip: zlib.createGzip
20 + , deflate: zlib.createDeflate
21 +};
22 +
23 +/**
24 + * Default filter function.
25 + */
26 +
27 +exports.filter = function(req, res){
28 + return /json|text|javascript/.test(res.getHeader('Content-Type'));
29 +};
30 +
31 +/**
32 + * Compress:
33 + *
34 + * Compress response data with gzip/deflate.
35 + *
36 + * Filter:
37 + *
38 + * A `filter` callback function may be passed to
39 + * replace the default logic of:
40 + *
41 + * exports.filter = function(req, res){
42 + * return /json|text|javascript/.test(res.getHeader('Content-Type'));
43 + * };
44 + *
45 + * Options:
46 + *
47 + * All remaining options are passed to the gzip/deflate
48 + * creation functions. Consult node's docs for additional details.
49 + *
50 + * - `chunkSize` (default: 16*1024)
51 + * - `windowBits`
52 + * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
53 + * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
54 + * - `strategy`: compression strategy
55 + *
56 + * @param {Object} options
57 + * @return {Function}
58 + * @api public
59 + */
60 +
61 +module.exports = function compress(options) {
62 + var options = options || {}
63 + , names = Object.keys(exports.methods)
64 + , filter = options.filter || exports.filter;
65 +
66 + return function(req, res, next){
67 + var accept = req.headers['accept-encoding']
68 + , write = res.write
69 + , end = res.end
70 + , stream
71 + , method;
72 +
73 + // vary
74 + res.setHeader('Vary', 'Accept-Encoding');
75 +
76 + // proxy
77 +
78 + res.write = function(chunk, encoding){
79 + if (!this.headerSent) this._implicitHeader();
80 + return stream
81 + ? stream.write(new Buffer(chunk, encoding))
82 + : write.call(res, chunk, encoding);
83 + };
84 +
85 + res.end = function(chunk, encoding){
86 + if (chunk) this.write(chunk, encoding);
87 + return stream
88 + ? stream.end()
89 + : end.call(res);
90 + };
91 +
92 + res.on('header', function(){
93 + var encoding = res.getHeader('Content-Encoding') || 'identity';
94 +
95 + // already encoded
96 + if ('identity' != encoding) return;
97 +
98 + // default request filter
99 + if (!filter(req, res)) return;
100 +
101 + // SHOULD use identity
102 + if (!accept) return;
103 +
104 + // head
105 + if ('HEAD' == req.method) return;
106 +
107 + // default to gzip
108 + if ('*' == accept.trim()) method = 'gzip';
109 +
110 + // compression method
111 + if (!method) {
112 + for (var i = 0, len = names.length; i < len; ++i) {
113 + if (~accept.indexOf(names[i])) {
114 + method = names[i];
115 + break;
116 + }
117 + }
118 + }
119 +
120 + // compression method
121 + if (!method) return;
122 +
123 + // compression stream
124 + stream = exports.methods[method](options);
125 +
126 + // header fields
127 + res.setHeader('Content-Encoding', method);
128 + res.removeHeader('Content-Length');
129 +
130 + // compression
131 +
132 + stream.on('data', function(chunk){
133 + write.call(res, chunk);
134 + });
135 +
136 + stream.on('end', function(){
137 + end.call(res);
138 + });
139 +
140 + stream.on('drain', function() {
141 + res.emit('drain');
142 + });
143 + });
144 +
145 + next();
146 + };
147 +}
1 +
2 +/*!
3 + * Connect - cookieParser
4 + * Copyright(c) 2010 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var utils = require('./../utils')
14 + , cookie = require('cookie');
15 +
16 +/**
17 + * Cookie parser:
18 + *
19 + * Parse _Cookie_ header and populate `req.cookies`
20 + * with an object keyed by the cookie names. Optionally
21 + * you may enabled signed cookie support by passing
22 + * a `secret` string, which assigns `req.secret` so
23 + * it may be used by other middleware.
24 + *
25 + * Examples:
26 + *
27 + * connect()
28 + * .use(connect.cookieParser('optional secret string'))
29 + * .use(function(req, res, next){
30 + * res.end(JSON.stringify(req.cookies));
31 + * })
32 + *
33 + * @param {String} secret
34 + * @return {Function}
35 + * @api public
36 + */
37 +
38 +module.exports = function cookieParser(secret){
39 + return function cookieParser(req, res, next) {
40 + if (req.cookies) return next();
41 + var cookies = req.headers.cookie;
42 +
43 + req.secret = secret;
44 + req.cookies = {};
45 + req.signedCookies = {};
46 +
47 + if (cookies) {
48 + try {
49 + req.cookies = cookie.parse(cookies);
50 + if (secret) {
51 + req.signedCookies = utils.parseSignedCookies(req.cookies, secret);
52 + var obj = utils.parseJSONCookies(req.signedCookies);
53 + req.signedCookies = obj;
54 + }
55 + req.cookies = utils.parseJSONCookies(req.cookies);
56 + } catch (err) {
57 + err.status = 400;
58 + return next(err);
59 + }
60 + }
61 + next();
62 + };
63 +};
1 +
2 +/*!
3 + * Connect - cookieSession
4 + * Copyright(c) 2011 Sencha Inc.
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Module dependencies.
10 + */
11 +
12 +var utils = require('./../utils')
13 + , Cookie = require('./session/cookie')
14 + , debug = require('debug')('connect:cookieSession')
15 + , signature = require('cookie-signature')
16 + , crc16 = require('crc').crc16;
17 +
18 +// environment
19 +
20 +var env = process.env.NODE_ENV;
21 +
22 +/**
23 + * Cookie Session:
24 + *
25 + * Cookie session middleware.
26 + *
27 + * var app = connect();
28 + * app.use(connect.cookieParser());
29 + * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }}));
30 + *
31 + * Options:
32 + *
33 + * - `key` cookie name defaulting to `connect.sess`
34 + * - `secret` prevents cookie tampering
35 + * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
36 + * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
37 + *
38 + * Clearing sessions:
39 + *
40 + * To clear the session simply set its value to `null`,
41 + * `cookieSession()` will then respond with a 1970 Set-Cookie.
42 + *
43 + * req.session = null;
44 + *
45 + * @param {Object} options
46 + * @return {Function}
47 + * @api public
48 + */
49 +
50 +module.exports = function cookieSession(options){
51 + // TODO: utilize Session/Cookie to unify API
52 + var options = options || {}
53 + , key = options.key || 'connect.sess'
54 + , trustProxy = options.proxy;
55 +
56 + return function cookieSession(req, res, next) {
57 +
58 + // req.secret is for backwards compatibility
59 + var secret = options.secret || req.secret;
60 + if (!secret) throw new Error('`secret` option required for cookie sessions');
61 +
62 + // default session
63 + req.session = {};
64 + var cookie = req.session.cookie = new Cookie(options.cookie);
65 +
66 + // pathname mismatch
67 + if (0 != req.originalUrl.indexOf(cookie.path)) return next();
68 +
69 + // cookieParser secret
70 + if (!options.secret && req.secret) {
71 + req.session = req.signedCookies[key] || {};
72 + } else {
73 + // TODO: refactor
74 + var rawCookie = req.cookies[key];
75 + if (rawCookie) {
76 + var unsigned = utils.parseSignedCookie(rawCookie, secret);
77 + if (unsigned) {
78 + var originalHash = crc16(unsigned);
79 + req.session = utils.parseJSONCookie(unsigned) || {};
80 + }
81 + }
82 + }
83 +
84 + res.on('header', function(){
85 + // removed
86 + if (!req.session) {
87 + debug('clear session');
88 + cookie.expires = new Date(0);
89 + res.setHeader('Set-Cookie', cookie.serialize(key, ''));
90 + return;
91 + }
92 +
93 + delete req.session.cookie;
94 +
95 + // check security
96 + var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()
97 + , tls = req.connection.encrypted || (trustProxy && 'https' == proto)
98 + , secured = cookie.secure && tls;
99 +
100 + // only send secure cookies via https
101 + if (cookie.secure && !secured) return debug('not secured');
102 +
103 + // serialize
104 + debug('serializing %j', req.session);
105 + var val = 'j:' + JSON.stringify(req.session);
106 +
107 + // compare hashes, no need to set-cookie if unchanged
108 + if (originalHash == crc16(val)) return debug('unmodified session');
109 +
110 + // set-cookie
111 + val = 's:' + signature.sign(val, secret);
112 + val = cookie.serialize(key, val);
113 + debug('set-cookie %j', cookie);
114 + res.setHeader('Set-Cookie', val);
115 + });
116 +
117 + next();
118 + };
119 +};
1 +/*!
2 + * Connect - csrf
3 + * Copyright(c) 2011 Sencha Inc.
4 + * MIT Licensed
5 + */
6 +
7 +/**
8 + * Module dependencies.
9 + */
10 +
11 +var utils = require('../utils');
12 +
13 +/**
14 + * Anti CSRF:
15 + *
16 + * CRSF protection middleware.
17 + *
18 + * By default this middleware generates a token named "_csrf"
19 + * which should be added to requests which mutate
20 + * state, within a hidden form field, query-string etc. This
21 + * token is validated against the visitor's `req.session._csrf`
22 + * property.
23 + *
24 + * The default `value` function checks `req.body` generated
25 + * by the `bodyParser()` middleware, `req.query` generated
26 + * by `query()`, and the "X-CSRF-Token" header field.
27 + *
28 + * This middleware requires session support, thus should be added
29 + * somewhere _below_ `session()` and `cookieParser()`.
30 + *
31 + * Options:
32 + *
33 + * - `value` a function accepting the request, returning the token
34 + *
35 + * @param {Object} options
36 + * @api public
37 + */
38 +
39 +module.exports = function csrf(options) {
40 + var options = options || {}
41 + , value = options.value || defaultValue;
42 +
43 + return function(req, res, next){
44 + // generate CSRF token
45 + var token = req.session._csrf || (req.session._csrf = utils.uid(24));
46 +
47 + // ignore these methods
48 + if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next();
49 +
50 + // determine value
51 + var val = value(req);
52 +
53 + // check
54 + if (val != token) return next(utils.error(403));
55 +
56 + next();
57 + }
58 +};
59 +
60 +/**
61 + * Default value function, checking the `req.body`
62 + * and `req.query` for the CSRF token.
63 + *
64 + * @param {IncomingMessage} req
65 + * @return {String}
66 + * @api private
67 + */
68 +
69 +function defaultValue(req) {
70 + return (req.body && req.body._csrf)
71 + || (req.query && req.query._csrf)
72 + || (req.headers['x-csrf-token']);
73 +}
1 +
2 +/*!
3 + * Connect - directory
4 + * Copyright(c) 2011 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +// TODO: icon / style for directories
10 +// TODO: arrow key navigation
11 +// TODO: make icons extensible
12 +
13 +/**
14 + * Module dependencies.
15 + */
16 +
17 +var fs = require('fs')
18 + , parse = require('url').parse
19 + , utils = require('../utils')
20 + , path = require('path')
21 + , normalize = path.normalize
22 + , extname = path.extname
23 + , join = path.join;
24 +
25 +/*!
26 + * Icon cache.
27 + */
28 +
29 +var cache = {};
30 +
31 +/**
32 + * Directory:
33 + *
34 + * Serve directory listings with the given `root` path.
35 + *
36 + * Options:
37 + *
38 + * - `hidden` display hidden (dot) files. Defaults to false.
39 + * - `icons` display icons. Defaults to false.
40 + * - `filter` Apply this filter function to files. Defaults to false.
41 + *
42 + * @param {String} root
43 + * @param {Object} options
44 + * @return {Function}
45 + * @api public
46 + */
47 +
48 +exports = module.exports = function directory(root, options){
49 + options = options || {};
50 +
51 + // root required
52 + if (!root) throw new Error('directory() root path required');
53 + var hidden = options.hidden
54 + , icons = options.icons
55 + , filter = options.filter
56 + , root = normalize(root);
57 +
58 + return function directory(req, res, next) {
59 + if ('GET' != req.method && 'HEAD' != req.method) return next();
60 +
61 + var accept = req.headers.accept || 'text/plain'
62 + , url = parse(req.url)
63 + , dir = decodeURIComponent(url.pathname)
64 + , path = normalize(join(root, dir))
65 + , originalUrl = parse(req.originalUrl)
66 + , originalDir = decodeURIComponent(originalUrl.pathname)
67 + , showUp = path != root && path != root + '/';
68 +
69 + // null byte(s), bad request
70 + if (~path.indexOf('\0')) return next(utils.error(400));
71 +
72 + // malicious path, forbidden
73 + if (0 != path.indexOf(root)) return next(utils.error(403));
74 +
75 + // check if we have a directory
76 + fs.stat(path, function(err, stat){
77 + if (err) return 'ENOENT' == err.code
78 + ? next()
79 + : next(err);
80 +
81 + if (!stat.isDirectory()) return next();
82 +
83 + // fetch files
84 + fs.readdir(path, function(err, files){
85 + if (err) return next(err);
86 + if (!hidden) files = removeHidden(files);
87 + if (filter) files = files.filter(filter);
88 + files.sort();
89 +
90 + // content-negotiation
91 + for (var key in exports) {
92 + if (~accept.indexOf(key) || ~accept.indexOf('*/*')) {
93 + exports[key](req, res, files, next, originalDir, showUp, icons);
94 + return;
95 + }
96 + }
97 +
98 + // not acceptable
99 + next(utils.error(406));
100 + });
101 + });
102 + };
103 +};
104 +
105 +/**
106 + * Respond with text/html.
107 + */
108 +
109 +exports.html = function(req, res, files, next, dir, showUp, icons){
110 + fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){
111 + if (err) return next(err);
112 + fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){
113 + if (err) return next(err);
114 + if (showUp) files.unshift('..');
115 + str = str
116 + .replace('{style}', style)
117 + .replace('{files}', html(files, dir, icons))
118 + .replace('{directory}', dir)
119 + .replace('{linked-path}', htmlPath(dir));
120 + res.setHeader('Content-Type', 'text/html');
121 + res.setHeader('Content-Length', str.length);
122 + res.end(str);
123 + });
124 + });
125 +};
126 +
127 +/**
128 + * Respond with application/json.
129 + */
130 +
131 +exports.json = function(req, res, files){
132 + files = JSON.stringify(files);
133 + res.setHeader('Content-Type', 'application/json');
134 + res.setHeader('Content-Length', files.length);
135 + res.end(files);
136 +};
137 +
138 +/**
139 + * Respond with text/plain.
140 + */
141 +
142 +exports.plain = function(req, res, files){
143 + files = files.join('\n') + '\n';
144 + res.setHeader('Content-Type', 'text/plain');
145 + res.setHeader('Content-Length', files.length);
146 + res.end(files);
147 +};
148 +
149 +/**
150 + * Map html `dir`, returning a linked path.
151 + */
152 +
153 +function htmlPath(dir) {
154 + var curr = [];
155 + return dir.split('/').map(function(part){
156 + curr.push(part);
157 + return '<a href="' + curr.join('/') + '">' + part + '</a>';
158 + }).join(' / ');
159 +}
160 +
161 +/**
162 + * Map html `files`, returning an html unordered list.
163 + */
164 +
165 +function html(files, dir, useIcons) {
166 + return '<ul id="files">' + files.map(function(file){
167 + var icon = ''
168 + , classes = [];
169 +
170 + if (useIcons && '..' != file) {
171 + icon = icons[extname(file)] || icons.default;
172 + icon = '<img src="data:image/png;base64,' + load(icon) + '" />';
173 + classes.push('icon');
174 + }
175 +
176 + return '<li><a href="'
177 + + join(dir, file)
178 + + '" class="'
179 + + classes.join(' ') + '"'
180 + + ' title="' + file + '">'
181 + + icon + file + '</a></li>';
182 +
183 + }).join('\n') + '</ul>';
184 +}
185 +
186 +/**
187 + * Load and cache the given `icon`.
188 + *
189 + * @param {String} icon
190 + * @return {String}
191 + * @api private
192 + */
193 +
194 +function load(icon) {
195 + if (cache[icon]) return cache[icon];
196 + return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64');
197 +}
198 +
199 +/**
200 + * Filter "hidden" `files`, aka files
201 + * beginning with a `.`.
202 + *
203 + * @param {Array} files
204 + * @return {Array}
205 + * @api private
206 + */
207 +
208 +function removeHidden(files) {
209 + return files.filter(function(file){
210 + return '.' != file[0];
211 + });
212 +}
213 +
214 +/**
215 + * Icon map.
216 + */
217 +
218 +var icons = {
219 + '.js': 'page_white_code_red.png'
220 + , '.c': 'page_white_c.png'
221 + , '.h': 'page_white_h.png'
222 + , '.cc': 'page_white_cplusplus.png'
223 + , '.php': 'page_white_php.png'
224 + , '.rb': 'page_white_ruby.png'
225 + , '.cpp': 'page_white_cplusplus.png'
226 + , '.swf': 'page_white_flash.png'
227 + , '.pdf': 'page_white_acrobat.png'
228 + , 'default': 'page_white.png'
229 +};
1 +/*!
2 + * Connect - errorHandler
3 + * Copyright(c) 2010 Sencha Inc.
4 + * Copyright(c) 2011 TJ Holowaychuk
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Module dependencies.
10 + */
11 +
12 +var utils = require('../utils')
13 + , fs = require('fs');
14 +
15 +// environment
16 +
17 +var env = process.env.NODE_ENV || 'development';
18 +
19 +/**
20 + * Error handler:
21 + *
22 + * Development error handler, providing stack traces
23 + * and error message responses for requests accepting text, html,
24 + * or json.
25 + *
26 + * Text:
27 + *
28 + * By default, and when _text/plain_ is accepted a simple stack trace
29 + * or error message will be returned.
30 + *
31 + * JSON:
32 + *
33 + * When _application/json_ is accepted, connect will respond with
34 + * an object in the form of `{ "error": error }`.
35 + *
36 + * HTML:
37 + *
38 + * When accepted connect will output a nice html stack trace.
39 + *
40 + * @return {Function}
41 + * @api public
42 + */
43 +
44 +exports = module.exports = function errorHandler(){
45 + return function errorHandler(err, req, res, next){
46 + if (err.status) res.statusCode = err.status;
47 + if (res.statusCode < 400) res.statusCode = 500;
48 + if ('test' != env) console.error(err.stack);
49 + var accept = req.headers.accept || '';
50 + // html
51 + if (~accept.indexOf('html')) {
52 + fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){
53 + fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){
54 + var stack = (err.stack || '')
55 + .split('\n').slice(1)
56 + .map(function(v){ return '<li>' + v + '</li>'; }).join('');
57 + html = html
58 + .replace('{style}', style)
59 + .replace('{stack}', stack)
60 + .replace('{title}', exports.title)
61 + .replace('{statusCode}', res.statusCode)
62 + .replace(/\{error\}/g, utils.escape(err.toString()));
63 + res.setHeader('Content-Type', 'text/html; charset=utf-8');
64 + res.end(html);
65 + });
66 + });
67 + // json
68 + } else if (~accept.indexOf('json')) {
69 + var error = { message: err.message, stack: err.stack };
70 + for (var prop in err) error[prop] = err[prop];
71 + var json = JSON.stringify({ error: error });
72 + res.setHeader('Content-Type', 'application/json');
73 + res.end(json);
74 + // plain text
75 + } else {
76 + res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' });
77 + res.end(err.stack);
78 + }
79 + };
80 +};
81 +
82 +/**
83 + * Template title, framework authors may override this value.
84 + */
85 +
86 +exports.title = 'Connect';
1 +
2 +/*!
3 + * Connect - favicon
4 + * Copyright(c) 2010 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var fs = require('fs')
14 + , utils = require('../utils');
15 +
16 +/**
17 + * Favicon:
18 + *
19 + * By default serves the connect favicon, or the favicon
20 + * located by the given `path`.
21 + *
22 + * Options:
23 + *
24 + * - `maxAge` cache-control max-age directive, defaulting to 1 day
25 + *
26 + * Examples:
27 + *
28 + * Serve default favicon:
29 + *
30 + * connect()
31 + * .use(connect.favicon())
32 + *
33 + * Serve favicon before logging for brevity:
34 + *
35 + * connect()
36 + * .use(connect.favicon())
37 + * .use(connect.logger('dev'))
38 + *
39 + * Serve custom favicon:
40 + *
41 + * connect()
42 + * .use(connect.favicon('public/favicon.ico))
43 + *
44 + * @param {String} path
45 + * @param {Object} options
46 + * @return {Function}
47 + * @api public
48 + */
49 +
50 +module.exports = function favicon(path, options){
51 + var options = options || {}
52 + , path = path || __dirname + '/../public/favicon.ico'
53 + , maxAge = options.maxAge || 86400000
54 + , icon; // favicon cache
55 +
56 + return function favicon(req, res, next){
57 + if ('/favicon.ico' == req.url) {
58 + if (icon) {
59 + res.writeHead(200, icon.headers);
60 + res.end(icon.body);
61 + } else {
62 + fs.readFile(path, function(err, buf){
63 + if (err) return next(err);
64 + icon = {
65 + headers: {
66 + 'Content-Type': 'image/x-icon'
67 + , 'Content-Length': buf.length
68 + , 'ETag': '"' + utils.md5(buf) + '"'
69 + , 'Cache-Control': 'public, max-age=' + (maxAge / 1000)
70 + },
71 + body: buf
72 + };
73 + res.writeHead(200, icon.headers);
74 + res.end(icon.body);
75 + });
76 + }
77 + } else {
78 + next();
79 + }
80 + };
81 +};
1 +
2 +/*!
3 + * Connect - json
4 + * Copyright(c) 2010 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var utils = require('../utils')
14 + , _limit = require('./limit');
15 +
16 +/**
17 + * noop middleware.
18 + */
19 +
20 +function noop(req, res, next) {
21 + next();
22 +}
23 +
24 +/**
25 + * JSON:
26 + *
27 + * Parse JSON request bodies, providing the
28 + * parsed object as `req.body`.
29 + *
30 + * Options:
31 + *
32 + * - `strict` when `false` anything `JSON.parse()` accepts will be parsed
33 + * - `reviver` used as the second "reviver" argument for JSON.parse
34 + * - `limit` byte limit disabled by default
35 + *
36 + * @param {Object} options
37 + * @return {Function}
38 + * @api public
39 + */
40 +
41 +exports = module.exports = function(options){
42 + var options = options || {}
43 + , strict = options.strict === false
44 + ? false
45 + : true;
46 +
47 + var limit = options.limit
48 + ? _limit(options.limit)
49 + : noop;
50 +
51 + return function json(req, res, next) {
52 + if (req._body) return next();
53 + req.body = req.body || {};
54 +
55 + // check Content-Type
56 + if ('application/json' != utils.mime(req)) return next();
57 +
58 + // flag as parsed
59 + req._body = true;
60 +
61 + // parse
62 + limit(req, res, function(err){
63 + if (err) return next(err);
64 + var buf = '';
65 + req.setEncoding('utf8');
66 + req.on('data', function(chunk){ buf += chunk });
67 + req.on('end', function(){
68 + if (strict && '{' != buf[0] && '[' != buf[0]) return next(utils.error(400, 'invalid json'));
69 + try {
70 + req.body = JSON.parse(buf, options.reviver);
71 + next();
72 + } catch (err){
73 + err.body = buf;
74 + err.status = 400;
75 + next(err);
76 + }
77 + });
78 + });
79 + }
80 +};
...\ No newline at end of file ...\ No newline at end of file
1 +
2 +/*!
3 + * Connect - limit
4 + * Copyright(c) 2011 TJ Holowaychuk
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Module dependencies.
10 + */
11 +
12 +var utils = require('../utils');
13 +
14 +/**
15 + * Limit:
16 + *
17 + * Limit request bodies to the given size in `bytes`.
18 + *
19 + * A string representation of the bytesize may also be passed,
20 + * for example "5mb", "200kb", "1gb", etc.
21 + *
22 + * connect()
23 + * .use(connect.limit('5.5mb'))
24 + * .use(handleImageUpload)
25 + *
26 + * @param {Number|String} bytes
27 + * @return {Function}
28 + * @api public
29 + */
30 +
31 +module.exports = function limit(bytes){
32 + if ('string' == typeof bytes) bytes = utils.parseBytes(bytes);
33 + if ('number' != typeof bytes) throw new Error('limit() bytes required');
34 + return function limit(req, res, next){
35 + var received = 0
36 + , len = req.headers['content-length']
37 + ? parseInt(req.headers['content-length'], 10)
38 + : null;
39 +
40 + // self-awareness
41 + if (req._limit) return next();
42 + req._limit = true;
43 +
44 + // limit by content-length
45 + if (len && len > bytes) return next(utils.error(413));
46 +
47 + // limit
48 + req.on('data', function(chunk){
49 + received += chunk.length;
50 + if (received > bytes) req.destroy();
51 + });
52 +
53 + next();
54 + };
55 +};
1 +/*!
2 + * Connect - logger
3 + * Copyright(c) 2010 Sencha Inc.
4 + * Copyright(c) 2011 TJ Holowaychuk
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Module dependencies.
10 + */
11 +
12 +var bytes = require('bytes');
13 +
14 +/*!
15 + * Log buffer.
16 + */
17 +
18 +var buf = [];
19 +
20 +/*!
21 + * Default log buffer duration.
22 + */
23 +
24 +var defaultBufferDuration = 1000;
25 +
26 +/**
27 + * Logger:
28 + *
29 + * Log requests with the given `options` or a `format` string.
30 + *
31 + * Options:
32 + *
33 + * - `format` Format string, see below for tokens
34 + * - `stream` Output stream, defaults to _stdout_
35 + * - `buffer` Buffer duration, defaults to 1000ms when _true_
36 + * - `immediate` Write log line on request instead of response (for response times)
37 + *
38 + * Tokens:
39 + *
40 + * - `:req[header]` ex: `:req[Accept]`
41 + * - `:res[header]` ex: `:res[Content-Length]`
42 + * - `:http-version`
43 + * - `:response-time`
44 + * - `:remote-addr`
45 + * - `:date`
46 + * - `:method`
47 + * - `:url`
48 + * - `:referrer`
49 + * - `:user-agent`
50 + * - `:status`
51 + *
52 + * Formats:
53 + *
54 + * Pre-defined formats that ship with connect:
55 + *
56 + * - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
57 + * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
58 + * - `tiny` ':method :url :status :res[content-length] - :response-time ms'
59 + * - `dev` concise output colored by response status for development use
60 + *
61 + * Examples:
62 + *
63 + * connect.logger() // default
64 + * connect.logger('short')
65 + * connect.logger('tiny')
66 + * connect.logger({ immediate: true, format: 'dev' })
67 + * connect.logger(':method :url - :referrer')
68 + * connect.logger(':req[content-type] -> :res[content-type]')
69 + * connect.logger(function(req, res){ return 'some format string' })
70 + *
71 + * Defining Tokens:
72 + *
73 + * To define a token, simply invoke `connect.logger.token()` with the
74 + * name and a callback function. The value returned is then available
75 + * as ":type" in this case.
76 + *
77 + * connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
78 + *
79 + * Defining Formats:
80 + *
81 + * All default formats are defined this way, however it's public API as well:
82 + *
83 + * connect.logger.format('name', 'string or function')
84 + *
85 + * @param {String|Function|Object} format or options
86 + * @return {Function}
87 + * @api public
88 + */
89 +
90 +exports = module.exports = function logger(options) {
91 + if ('object' == typeof options) {
92 + options = options || {};
93 + } else if (options) {
94 + options = { format: options };
95 + } else {
96 + options = {};
97 + }
98 +
99 + // output on request instead of response
100 + var immediate = options.immediate;
101 +
102 + // format name
103 + var fmt = exports[options.format] || options.format || exports.default;
104 +
105 + // compile format
106 + if ('function' != typeof fmt) fmt = compile(fmt);
107 +
108 + // options
109 + var stream = options.stream || process.stdout
110 + , buffer = options.buffer;
111 +
112 + // buffering support
113 + if (buffer) {
114 + var realStream = stream
115 + , interval = 'number' == typeof buffer
116 + ? buffer
117 + : defaultBufferDuration;
118 +
119 + // flush interval
120 + setInterval(function(){
121 + if (buf.length) {
122 + realStream.write(buf.join(''));
123 + buf.length = 0;
124 + }
125 + }, interval);
126 +
127 + // swap the stream
128 + stream = {
129 + write: function(str){
130 + buf.push(str);
131 + }
132 + };
133 + }
134 +
135 + return function logger(req, res, next) {
136 + req._startTime = new Date;
137 +
138 + // immediate
139 + if (immediate) {
140 + var line = fmt(exports, req, res);
141 + if (null == line) return;
142 + stream.write(line + '\n');
143 + // proxy end to output logging
144 + } else {
145 + var end = res.end;
146 + res.end = function(chunk, encoding){
147 + res.end = end;
148 + res.end(chunk, encoding);
149 + var line = fmt(exports, req, res);
150 + if (null == line) return;
151 + stream.write(line + '\n');
152 + };
153 + }
154 +
155 +
156 + next();
157 + };
158 +};
159 +
160 +/**
161 + * Compile `fmt` into a function.
162 + *
163 + * @param {String} fmt
164 + * @return {Function}
165 + * @api private
166 + */
167 +
168 +function compile(fmt) {
169 + fmt = fmt.replace(/"/g, '\\"');
170 + var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
171 + return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
172 + }) + '";'
173 + return new Function('tokens, req, res', js);
174 +};
175 +
176 +/**
177 + * Define a token function with the given `name`,
178 + * and callback `fn(req, res)`.
179 + *
180 + * @param {String} name
181 + * @param {Function} fn
182 + * @return {Object} exports for chaining
183 + * @api public
184 + */
185 +
186 +exports.token = function(name, fn) {
187 + exports[name] = fn;
188 + return this;
189 +};
190 +
191 +/**
192 + * Define a `fmt` with the given `name`.
193 + *
194 + * @param {String} name
195 + * @param {String|Function} fmt
196 + * @return {Object} exports for chaining
197 + * @api public
198 + */
199 +
200 +exports.format = function(name, str){
201 + exports[name] = str;
202 + return this;
203 +};
204 +
205 +/**
206 + * Default format.
207 + */
208 +
209 +exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');
210 +
211 +/**
212 + * Short format.
213 + */
214 +
215 +exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');
216 +
217 +/**
218 + * Tiny format.
219 + */
220 +
221 +exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');
222 +
223 +/**
224 + * dev (colored)
225 + */
226 +
227 +exports.format('dev', function(tokens, req, res){
228 + var status = res.statusCode
229 + , len = parseInt(res.getHeader('Content-Length'), 10)
230 + , color = 32;
231 +
232 + if (status >= 500) color = 31
233 + else if (status >= 400) color = 33
234 + else if (status >= 300) color = 36;
235 +
236 + len = isNaN(len)
237 + ? ''
238 + : len = ' - ' + bytes(len);
239 +
240 + return '\033[90m' + req.method
241 + + ' ' + req.originalUrl + ' '
242 + + '\033[' + color + 'm' + res.statusCode
243 + + ' \033[90m'
244 + + (new Date - req._startTime)
245 + + 'ms' + len
246 + + '\033[0m';
247 +});
248 +
249 +/**
250 + * request url
251 + */
252 +
253 +exports.token('url', function(req){
254 + return req.originalUrl || req.url;
255 +});
256 +
257 +/**
258 + * request method
259 + */
260 +
261 +exports.token('method', function(req){
262 + return req.method;
263 +});
264 +
265 +/**
266 + * response time in milliseconds
267 + */
268 +
269 +exports.token('response-time', function(req){
270 + return new Date - req._startTime;
271 +});
272 +
273 +/**
274 + * UTC date
275 + */
276 +
277 +exports.token('date', function(){
278 + return new Date().toUTCString();
279 +});
280 +
281 +/**
282 + * response status code
283 + */
284 +
285 +exports.token('status', function(req, res){
286 + return res.statusCode;
287 +});
288 +
289 +/**
290 + * normalized referrer
291 + */
292 +
293 +exports.token('referrer', function(req){
294 + return req.headers['referer'] || req.headers['referrer'];
295 +});
296 +
297 +/**
298 + * remote address
299 + */
300 +
301 +exports.token('remote-addr', function(req){
302 + return req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress));
303 +});
304 +
305 +/**
306 + * HTTP version
307 + */
308 +
309 +exports.token('http-version', function(req){
310 + return req.httpVersionMajor + '.' + req.httpVersionMinor;
311 +});
312 +
313 +/**
314 + * UA string
315 + */
316 +
317 +exports.token('user-agent', function(req){
318 + return req.headers['user-agent'];
319 +});
320 +
321 +/**
322 + * request header
323 + */
324 +
325 +exports.token('req', function(req, res, field){
326 + return req.headers[field.toLowerCase()];
327 +});
328 +
329 +/**
330 + * response header
331 + */
332 +
333 +exports.token('res', function(req, res, field){
334 + return (res._headers || {})[field.toLowerCase()];
335 +});
336 +
1 +
2 +/*!
3 + * Connect - methodOverride
4 + * Copyright(c) 2010 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +/**
10 + * Method Override:
11 + *
12 + * Provides faux HTTP method support.
13 + *
14 + * Pass an optional `key` to use when checking for
15 + * a method override, othewise defaults to _\_method_.
16 + * The original method is available via `req.originalMethod`.
17 + *
18 + * @param {String} key
19 + * @return {Function}
20 + * @api public
21 + */
22 +
23 +module.exports = function methodOverride(key){
24 + key = key || "_method";
25 + return function methodOverride(req, res, next) {
26 + req.originalMethod = req.originalMethod || req.method;
27 +
28 + // req.body
29 + if (req.body && key in req.body) {
30 + req.method = req.body[key].toUpperCase();
31 + delete req.body[key];
32 + // check X-HTTP-Method-Override
33 + } else if (req.headers['x-http-method-override']) {
34 + req.method = req.headers['x-http-method-override'].toUpperCase();
35 + }
36 +
37 + next();
38 + };
39 +};
40 +
1 +/*!
2 + * Connect - multipart
3 + * Copyright(c) 2010 Sencha Inc.
4 + * Copyright(c) 2011 TJ Holowaychuk
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Module dependencies.
10 + */
11 +
12 +var formidable = require('formidable')
13 + , _limit = require('./limit')
14 + , utils = require('../utils')
15 + , qs = require('qs');
16 +
17 +/**
18 + * noop middleware.
19 + */
20 +
21 +function noop(req, res, next) {
22 + next();
23 +}
24 +
25 +/**
26 + * Multipart:
27 + *
28 + * Parse multipart/form-data request bodies,
29 + * providing the parsed object as `req.body`
30 + * and `req.files`.
31 + *
32 + * Configuration:
33 + *
34 + * The options passed are merged with [formidable](https://github.com/felixge/node-formidable)'s
35 + * `IncomingForm` object, allowing you to configure the upload directory,
36 + * size limits, etc. For example if you wish to change the upload dir do the following.
37 + *
38 + * app.use(connect.multipart({ uploadDir: path }));
39 + *
40 + * Options:
41 + *
42 + * - `limit` byte limit defaulting to none
43 + * - `defer` defers processing and exposes the Formidable form object as `req.form`.
44 + * `next()` is called without waiting for the form's "end" event.
45 + * This option is useful if you need to bind to the "progress" event, for example.
46 + *
47 + * @param {Object} options
48 + * @return {Function}
49 + * @api public
50 + */
51 +
52 +exports = module.exports = function(options){
53 + options = options || {};
54 +
55 + var limit = options.limit
56 + ? _limit(options.limit)
57 + : noop;
58 +
59 + return function multipart(req, res, next) {
60 + if (req._body) return next();
61 + req.body = req.body || {};
62 + req.files = req.files || {};
63 +
64 + // ignore GET
65 + if ('GET' == req.method || 'HEAD' == req.method) return next();
66 +
67 + // check Content-Type
68 + if ('multipart/form-data' != utils.mime(req)) return next();
69 +
70 + // flag as parsed
71 + req._body = true;
72 +
73 + // parse
74 + limit(req, res, function(err){
75 + if (err) return next(err);
76 +
77 + var form = new formidable.IncomingForm
78 + , data = {}
79 + , files = {}
80 + , done;
81 +
82 + Object.keys(options).forEach(function(key){
83 + form[key] = options[key];
84 + });
85 +
86 + function ondata(name, val, data){
87 + if (Array.isArray(data[name])) {
88 + data[name].push(val);
89 + } else if (data[name]) {
90 + data[name] = [data[name], val];
91 + } else {
92 + data[name] = val;
93 + }
94 + }
95 +
96 + form.on('field', function(name, val){
97 + ondata(name, val, data);
98 + });
99 +
100 + form.on('file', function(name, val){
101 + ondata(name, val, files);
102 + });
103 +
104 + form.on('error', function(err){
105 + if (!options.defer) {
106 + err.status = 400;
107 + next(err);
108 + }
109 + done = true;
110 + });
111 +
112 + form.on('end', function(){
113 + if (done) return;
114 + try {
115 + req.body = qs.parse(data);
116 + req.files = qs.parse(files);
117 + if (!options.defer) next();
118 + } catch (err) {
119 + form.emit('error', err);
120 + }
121 + });
122 +
123 + form.parse(req);
124 +
125 + if (options.defer) {
126 + req.form = form;
127 + next();
128 + }
129 + });
130 + }
131 +};
1 +/*!
2 + * Connect - query
3 + * Copyright(c) 2011 TJ Holowaychuk
4 + * Copyright(c) 2011 Sencha Inc.
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Module dependencies.
10 + */
11 +
12 +var qs = require('qs')
13 + , parse = require('../utils').parseUrl;
14 +
15 +/**
16 + * Query:
17 + *
18 + * Automatically parse the query-string when available,
19 + * populating the `req.query` object.
20 + *
21 + * Examples:
22 + *
23 + * connect()
24 + * .use(connect.query())
25 + * .use(function(req, res){
26 + * res.end(JSON.stringify(req.query));
27 + * });
28 + *
29 + * The `options` passed are provided to qs.parse function.
30 + *
31 + * @param {Object} options
32 + * @return {Function}
33 + * @api public
34 + */
35 +
36 +module.exports = function query(options){
37 + return function query(req, res, next){
38 + if (!req.query) {
39 + req.query = ~req.url.indexOf('?')
40 + ? qs.parse(parse(req).query, options)
41 + : {};
42 + }
43 +
44 + next();
45 + };
46 +};
1 +
2 +/*!
3 + * Connect - responseTime
4 + * Copyright(c) 2011 TJ Holowaychuk
5 + * MIT Licensed
6 + */
7 +
8 +/**
9 + * Reponse time:
10 + *
11 + * Adds the `X-Response-Time` header displaying the response
12 + * duration in milliseconds.
13 + *
14 + * @return {Function}
15 + * @api public
16 + */
17 +
18 +module.exports = function responseTime(){
19 + return function(req, res, next){
20 + var start = new Date;
21 +
22 + if (res._responseTime) return next();
23 + res._responseTime = true;
24 +
25 + res.on('header', function(){
26 + var duration = new Date - start;
27 + res.setHeader('X-Response-Time', duration + 'ms');
28 + });
29 +
30 + next();
31 + };
32 +};
1 +
2 +/*!
3 + * Connect - session
4 + * Copyright(c) 2010 Sencha Inc.
5 + * Copyright(c) 2011 TJ Holowaychuk
6 + * MIT Licensed
7 + */
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var Session = require('./session/session')
14 + , debug = require('debug')('connect:session')
15 + , MemoryStore = require('./session/memory')
16 + , signature = require('cookie-signature')
17 + , Cookie = require('./session/cookie')
18 + , Store = require('./session/store')
19 + , utils = require('./../utils')
20 + , parse = utils.parseUrl
21 + , crc16 = require('crc').crc16;
22 +
23 +// environment
24 +
25 +var env = process.env.NODE_ENV;
26 +
27 +/**
28 + * Expose the middleware.
29 + */
30 +
31 +exports = module.exports = session;
32 +
33 +/**
34 + * Expose constructors.
35 + */
36 +
37 +exports.Store = Store;
38 +exports.Cookie = Cookie;
39 +exports.Session = Session;
40 +exports.MemoryStore = MemoryStore;
41 +
42 +/**
43 + * Warning message for `MemoryStore` usage in production.
44 + */
45 +
46 +var warning = 'Warning: connection.session() MemoryStore is not\n'
47 + + 'designed for a production environment, as it will leak\n'
48 + + 'memory, and will not scale past a single process.';
49 +
50 +/**
51 + * Session:
52 + *
53 + * Setup session store with the given `options`.
54 + *
55 + * Session data is _not_ saved in the cookie itself, however
56 + * cookies are used, so we must use the [cookieParser()](cookieParser.html)
57 + * middleware _before_ `session()`.
58 + *
59 + * Examples:
60 + *
61 + * connect()
62 + * .use(connect.cookieParser())
63 + * .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }}))
64 + *
65 + * Options:
66 + *
67 + * - `key` cookie name defaulting to `connect.sid`
68 + * - `store` session store instance
69 + * - `secret` session cookie is signed with this secret to prevent tampering
70 + * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
71 + * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
72 + *
73 + * Cookie option:
74 + *
75 + * By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set
76 + * so the cookie becomes a browser-session cookie. When the user closes the
77 + * browser the cookie (and session) will be removed.
78 + *
79 + * ## req.session
80 + *
81 + * To store or access session data, simply use the request property `req.session`,
82 + * which is (generally) serialized as JSON by the store, so nested objects
83 + * are typically fine. For example below is a user-specific view counter:
84 + *
85 + * connect()
86 + * .use(connect.favicon())
87 + * .use(connect.cookieParser())
88 + * .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
89 + * .use(function(req, res, next){
90 + * var sess = req.session;
91 + * if (sess.views) {
92 + * res.setHeader('Content-Type', 'text/html');
93 + * res.write('<p>views: ' + sess.views + '</p>');
94 + * res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>');
95 + * res.end();
96 + * sess.views++;
97 + * } else {
98 + * sess.views = 1;
99 + * res.end('welcome to the session demo. refresh!');
100 + * }
101 + * }
102 + * )).listen(3000);
103 + *
104 + * ## Session#regenerate()
105 + *
106 + * To regenerate the session simply invoke the method, once complete
107 + * a new SID and `Session` instance will be initialized at `req.session`.
108 + *
109 + * req.session.regenerate(function(err){
110 + * // will have a new session here
111 + * });
112 + *
113 + * ## Session#destroy()
114 + *
115 + * Destroys the session, removing `req.session`, will be re-generated next request.
116 + *
117 + * req.session.destroy(function(err){
118 + * // cannot access session here
119 + * });
120 + *
121 + * ## Session#reload()
122 + *
123 + * Reloads the session data.
124 + *
125 + * req.session.reload(function(err){
126 + * // session updated
127 + * });
128 + *
129 + * ## Session#save()
130 + *
131 + * Save the session.
132 + *
133 + * req.session.save(function(err){
134 + * // session saved
135 + * });
136 + *
137 + * ## Session#touch()
138 + *
139 + * Updates the `.maxAge` property. Typically this is
140 + * not necessary to call, as the session middleware does this for you.
141 + *
142 + * ## Session#cookie
143 + *
144 + * Each session has a unique cookie object accompany it. This allows
145 + * you to alter the session cookie per visitor. For example we can
146 + * set `req.session.cookie.expires` to `false` to enable the cookie
147 + * to remain for only the duration of the user-agent.
148 + *
149 + * ## Session#maxAge
150 + *
151 + * Alternatively `req.session.cookie.maxAge` will return the time
152 + * remaining in milliseconds, which we may also re-assign a new value
153 + * to adjust the `.expires` property appropriately. The following
154 + * are essentially equivalent
155 + *
156 + * var hour = 3600000;
157 + * req.session.cookie.expires = new Date(Date.now() + hour);
158 + * req.session.cookie.maxAge = hour;
159 + *
160 + * For example when `maxAge` is set to `60000` (one minute), and 30 seconds
161 + * has elapsed it will return `30000` until the current request has completed,
162 + * at which time `req.session.touch()` is called to reset `req.session.maxAge`
163 + * to its original value.
164 + *
165 + * req.session.cookie.maxAge;
166 + * // => 30000
167 + *
168 + * Session Store Implementation:
169 + *
170 + * Every session store _must_ implement the following methods
171 + *
172 + * - `.get(sid, callback)`
173 + * - `.set(sid, session, callback)`
174 + * - `.destroy(sid, callback)`
175 + *
176 + * Recommended methods include, but are not limited to:
177 + *
178 + * - `.length(callback)`
179 + * - `.clear(callback)`
180 + *
181 + * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo.
182 + *
183 + * @param {Object} options
184 + * @return {Function}
185 + * @api public
186 + */
187 +
188 +function session(options){
189 + var options = options || {}
190 + , key = options.key || 'connect.sid'
191 + , store = options.store || new MemoryStore
192 + , cookie = options.cookie || {}
193 + , trustProxy = options.proxy
194 + , storeReady = true;
195 +
196 + // notify user that this store is not
197 + // meant for a production environment
198 + if ('production' == env && store instanceof MemoryStore) {
199 + console.warn(warning);
200 + }
201 +
202 + // generates the new session
203 + store.generate = function(req){
204 + req.sessionID = utils.uid(24);
205 + req.session = new Session(req);
206 + req.session.cookie = new Cookie(cookie);
207 + };
208 +
209 + store.on('disconnect', function(){ storeReady = false; });
210 + store.on('connect', function(){ storeReady = true; });
211 +
212 + return function session(req, res, next) {
213 + // self-awareness
214 + if (req.session) return next();
215 +
216 + // Handle connection as if there is no session if
217 + // the store has temporarily disconnected etc
218 + if (!storeReady) return debug('store is disconnected'), next();
219 +
220 + // pathname mismatch
221 + if (0 != req.originalUrl.indexOf(cookie.path || '/')) return next();
222 +
223 + // backwards compatibility for signed cookies
224 + // req.secret is passed from the cookie parser middleware
225 + var secret = options.secret || req.secret;
226 +
227 + // ensure secret is available or bail
228 + if (!secret) throw new Error('`secret` option required for sessions');
229 +
230 + // parse url
231 + var url = parse(req)
232 + , path = url.pathname
233 + , originalHash
234 + , originalId;
235 +
236 + // expose store
237 + req.sessionStore = store;
238 +
239 + // grab the session cookie value and check the signature
240 + var rawCookie = req.cookies[key];
241 +
242 + // get signedCookies for backwards compat with signed cookies
243 + var unsignedCookie = req.signedCookies[key];
244 +
245 + if (!unsignedCookie && rawCookie) {
246 + unsignedCookie = utils.parseSignedCookie(rawCookie, secret);
247 + }
248 +
249 + // set-cookie
250 + res.on('header', function(){
251 + if (!req.session) return;
252 + var cookie = req.session.cookie
253 + , proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()
254 + , tls = req.connection.encrypted || (trustProxy && 'https' == proto)
255 + , secured = cookie.secure && tls
256 + , isNew = unsignedCookie != req.sessionID;
257 +
258 + // only send secure cookies via https
259 + if (cookie.secure && !secured) return debug('not secured');
260 +
261 + // browser-session length cookie
262 + if (null == cookie.expires) {
263 + if (!isNew) return debug('already set browser-session cookie');
264 + // compare hashes and ids
265 + } else if (originalHash == hash(req.session) && originalId == req.session.id) {
266 + return debug('unmodified session');
267 + }
268 +
269 + var val = 's:' + signature.sign(req.sessionID, secret);
270 + val = cookie.serialize(key, val);
271 + debug('set-cookie %s', val);
272 + res.setHeader('Set-Cookie', val);
273 + });
274 +
275 + // proxy end() to commit the session
276 + var end = res.end;
277 + res.end = function(data, encoding){
278 + res.end = end;
279 + if (!req.session) return res.end(data, encoding);
280 + debug('saving');
281 + req.session.resetMaxAge();
282 + req.session.save(function(){
283 + debug('saved');
284 + res.end(data, encoding);
285 + });
286 + };
287 +
288 + // generate the session
289 + function generate() {
290 + store.generate(req);
291 + }
292 +
293 + // get the sessionID from the cookie
294 + req.sessionID = unsignedCookie;
295 +
296 + // generate a session if the browser doesn't send a sessionID
297 + if (!req.sessionID) {
298 + debug('no SID sent, generating session');
299 + generate();
300 + next();
301 + return;
302 + }
303 +
304 + // generate the session object
305 + var pause = utils.pause(req);
306 + debug('fetching %s', req.sessionID);
307 + store.get(req.sessionID, function(err, sess){
308 + // proxy to resume() events
309 + var _next = next;
310 + next = function(err){
311 + _next(err);
312 + pause.resume();
313 + }
314 +
315 + // error handling
316 + if (err) {
317 + debug('error');
318 + if ('ENOENT' == err.code) {
319 + generate();
320 + next();
321 + } else {
322 + next(err);
323 + }
324 + // no session
325 + } else if (!sess) {
326 + debug('no session found');
327 + generate();
328 + next();
329 + // populate req.session
330 + } else {
331 + debug('session found');
332 + store.createSession(req, sess);
333 + originalId = req.sessionID;
334 + originalHash = hash(sess);
335 + next();
336 + }
337 + });
338 + };
339 +};
340 +
341 +/**
342 + * Hash the given `sess` object omitting changes
343 + * to `.cookie`.
344 + *
345 + * @param {Object} sess
346 + * @return {String}
347 + * @api private
348 + */
349 +
350 +function hash(sess) {
351 + return crc16(JSON.stringify(sess, function(key, val){
352 + if ('cookie' != key) return val;
353 + }));
354 +}
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.