최원섭

[Update] Express Version Modified

1 +var express = require('express');
2 +var path = require('path');
3 +var favicon = require('serve-favicon');
4 +var logger = require('morgan');
5 +var cookieParser = require('cookie-parser');
6 +var bodyParser = require('body-parser');
7 +
8 +var message = require('./routes/message');
9 +var keyboard = require('./routes/keyboard');
10 +var app = express();
11 +
12 +// view engine setup
13 +app.set('views', path.join(__dirname, 'views'));
14 +app.set('view engine', 'ejs');
15 +
16 +// uncomment after placing your favicon in /public
17 +//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
18 +app.use(logger('dev'));
19 +app.use(bodyParser.json());
20 +app.use(bodyParser.urlencoded({ extended: false }));
21 +app.use(cookieParser());
22 +app.use(express.static(path.join(__dirname, 'public')));
23 +
24 +app.use('/keyboard',keyboard);
25 +app.use('/message',message);
26 +
27 +// catch 404 and forward to error handler
28 +app.use(function(req, res, next) {
29 + var err = new Error('Not Found');
30 + err.status = 404;
31 + next(err);
32 +});
33 +
34 +// error handler
35 +app.use(function(err, req, res, next) {
36 + // set locals, only providing error in development
37 + res.locals.message = err.message;
38 + res.locals.error = req.app.get('env') === 'development' ? err : {};
39 +
40 + // render the error page
41 + res.status(err.status || 500);
42 + res.render('error');
43 +});
44 +
45 +module.exports = app;
46 +
1 +#!/usr/bin/env node
2 +
3 +/**
4 + * Module dependencies.
5 + */
6 +
7 +var app = require('../app');
8 +var debug = require('debug')('project:server');
9 +var http = require('http');
10 +
11 +/**
12 + * Get port from environment and store in Express.
13 + */
14 +
15 +var port = normalizePort(process.env.PORT || '80');
16 +app.set('port', port);
17 +
18 +/**
19 + * Create HTTP server.
20 + */
21 +
22 +var server = http.createServer(app);
23 +
24 +/**
25 + * Listen on provided port, on all network interfaces.
26 + */
27 +
28 +server.listen(port);
29 +server.on('error', onError);
30 +server.on('listening', onListening);
31 +
32 +/**
33 + * Normalize a port into a number, string, or false.
34 + */
35 +
36 +function normalizePort(val) {
37 + var port = parseInt(val, 10);
38 +
39 + if (isNaN(port)) {
40 + // named pipe
41 + return val;
42 + }
43 +
44 + if (port >= 0) {
45 + // port number
46 + return port;
47 + }
48 +
49 + return false;
50 +}
51 +
52 +/**
53 + * Event listener for HTTP server "error" event.
54 + */
55 +
56 +function onError(error) {
57 + if (error.syscall !== 'listen') {
58 + throw error;
59 + }
60 +
61 + var bind = typeof port === 'string'
62 + ? 'Pipe ' + port
63 + : 'Port ' + port;
64 +
65 + // handle specific listen errors with friendly messages
66 + switch (error.code) {
67 + case 'EACCES':
68 + console.error(bind + ' requires elevated privileges');
69 + process.exit(1);
70 + break;
71 + case 'EADDRINUSE':
72 + console.error(bind + ' is already in use');
73 + process.exit(1);
74 + break;
75 + default:
76 + throw error;
77 + }
78 +}
79 +
80 +/**
81 + * Event listener for HTTP server "listening" event.
82 + */
83 +
84 +function onListening() {
85 + var addr = server.address();
86 + var bind = typeof addr === 'string'
87 + ? 'pipe ' + addr
88 + : 'port ' + addr.port;
89 + debug('Listening on ' + bind);
90 +}
1 +2.0.0 / 2017-09-12
2 +==================
3 +
4 + * Drop support for Node.js below 0.8
5 + * Remove `auth(ctx)` signature -- pass in header or `auth(ctx.req)`
6 + * Use `safe-buffer` for improved Buffer API
7 +
8 +1.1.0 / 2016-11-18
9 +==================
10 +
11 + * Add `auth.parse` for low-level string parsing
12 +
13 +1.0.4 / 2016-05-10
14 +==================
15 +
16 + * Improve error message when `req` argument is not an object
17 + * Improve error message when `req` missing `headers` property
18 +
19 +1.0.3 / 2015-07-01
20 +==================
21 +
22 + * Fix regression accepting a Koa context
23 +
24 +1.0.2 / 2015-06-12
25 +==================
26 +
27 + * Improve error message when `req` argument missing
28 + * perf: enable strict mode
29 + * perf: hoist regular expression
30 + * perf: parse with regular expressions
31 + * perf: remove argument reassignment
32 +
33 +1.0.1 / 2015-05-04
34 +==================
35 +
36 + * Update readme
37 +
38 +1.0.0 / 2014-07-01
39 +==================
40 +
41 + * Support empty password
42 + * Support empty username
43 +
44 +0.0.1 / 2013-11-30
45 +==================
46 +
47 + * Initial release
1 +(The MIT License)
2 +
3 +Copyright (c) 2013 TJ Holowaychuk
4 +Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
5 +Copyright (c) 2015-2016 Douglas Christopher Wilson <doug@somethingdoug.com>
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.
1 +# basic-auth
2 +
3 +[![NPM Version][npm-image]][npm-url]
4 +[![NPM Downloads][downloads-image]][downloads-url]
5 +[![Node.js Version][node-version-image]][node-version-url]
6 +[![Build Status][travis-image]][travis-url]
7 +[![Test Coverage][coveralls-image]][coveralls-url]
8 +
9 +Generic basic auth Authorization header field parser for whatever.
10 +
11 +## Installation
12 +
13 +This is a [Node.js](https://nodejs.org/en/) module available through the
14 +[npm registry](https://www.npmjs.com/). Installation is done using the
15 +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
16 +
17 +```
18 +$ npm install basic-auth
19 +```
20 +
21 +## API
22 +
23 +<!-- eslint-disable no-unused-vars -->
24 +
25 +```js
26 +var auth = require('basic-auth')
27 +```
28 +
29 +### auth(req)
30 +
31 +Get the basic auth credentials from the given request. The `Authorization`
32 +header is parsed and if the header is invalid, `undefined` is returned,
33 +otherwise an object with `name` and `pass` properties.
34 +
35 +### auth.parse(string)
36 +
37 +Parse a basic auth authorization header string. This will return an object
38 +with `name` and `pass` properties, or `undefined` if the string is invalid.
39 +
40 +## Example
41 +
42 +Pass a Node.js request object to the module export. If parsing fails
43 +`undefined` is returned, otherwise an object with `.name` and `.pass`.
44 +
45 +<!-- eslint-disable no-unused-vars, no-undef -->
46 +
47 +```js
48 +var auth = require('basic-auth')
49 +var user = auth(req)
50 +// => { name: 'something', pass: 'whatever' }
51 +```
52 +
53 +A header string from any other location can also be parsed with
54 +`auth.parse`, for example a `Proxy-Authorization` header:
55 +
56 +<!-- eslint-disable no-unused-vars, no-undef -->
57 +
58 +```js
59 +var auth = require('basic-auth')
60 +var user = auth.parse(req.getHeader('Proxy-Authorization'))
61 +```
62 +
63 +### With vanilla node.js http server
64 +
65 +```js
66 +var http = require('http')
67 +var auth = require('basic-auth')
68 +
69 +// Create server
70 +var server = http.createServer(function (req, res) {
71 + var credentials = auth(req)
72 +
73 + if (!credentials || credentials.name !== 'john' || credentials.pass !== 'secret') {
74 + res.statusCode = 401
75 + res.setHeader('WWW-Authenticate', 'Basic realm="example"')
76 + res.end('Access denied')
77 + } else {
78 + res.end('Access granted')
79 + }
80 +})
81 +
82 +// Listen
83 +server.listen(3000)
84 +```
85 +
86 +# License
87 +
88 +[MIT](LICENSE)
89 +
90 +[npm-image]: https://img.shields.io/npm/v/basic-auth.svg
91 +[npm-url]: https://npmjs.org/package/basic-auth
92 +[node-version-image]: https://img.shields.io/node/v/basic-auth.svg
93 +[node-version-url]: https://nodejs.org/en/download
94 +[travis-image]: https://img.shields.io/travis/jshttp/basic-auth/master.svg
95 +[travis-url]: https://travis-ci.org/jshttp/basic-auth
96 +[coveralls-image]: https://img.shields.io/coveralls/jshttp/basic-auth/master.svg
97 +[coveralls-url]: https://coveralls.io/r/jshttp/basic-auth?branch=master
98 +[downloads-image]: https://img.shields.io/npm/dm/basic-auth.svg
99 +[downloads-url]: https://npmjs.org/package/basic-auth
1 +/*!
2 + * basic-auth
3 + * Copyright(c) 2013 TJ Holowaychuk
4 + * Copyright(c) 2014 Jonathan Ong
5 + * Copyright(c) 2015-2016 Douglas Christopher Wilson
6 + * MIT Licensed
7 + */
8 +
9 +'use strict'
10 +
11 +/**
12 + * Module dependencies.
13 + * @private
14 + */
15 +
16 +var Buffer = require('safe-buffer').Buffer
17 +
18 +/**
19 + * Module exports.
20 + * @public
21 + */
22 +
23 +module.exports = auth
24 +module.exports.parse = parse
25 +
26 +/**
27 + * RegExp for basic auth credentials
28 + *
29 + * credentials = auth-scheme 1*SP token68
30 + * auth-scheme = "Basic" ; case insensitive
31 + * token68 = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
32 + * @private
33 + */
34 +
35 +var CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/
36 +
37 +/**
38 + * RegExp for basic auth user/pass
39 + *
40 + * user-pass = userid ":" password
41 + * userid = *<TEXT excluding ":">
42 + * password = *TEXT
43 + * @private
44 + */
45 +
46 +var USER_PASS_REGEXP = /^([^:]*):(.*)$/
47 +
48 +/**
49 + * Parse the Authorization header field of a request.
50 + *
51 + * @param {object} req
52 + * @return {object} with .name and .pass
53 + * @public
54 + */
55 +
56 +function auth (req) {
57 + if (!req) {
58 + throw new TypeError('argument req is required')
59 + }
60 +
61 + if (typeof req !== 'object') {
62 + throw new TypeError('argument req is required to be an object')
63 + }
64 +
65 + // get header
66 + var header = getAuthorization(req)
67 +
68 + // parse header
69 + return parse(header)
70 +}
71 +
72 +/**
73 + * Decode base64 string.
74 + * @private
75 + */
76 +
77 +function decodeBase64 (str) {
78 + return Buffer.from(str, 'base64').toString()
79 +}
80 +
81 +/**
82 + * Get the Authorization header from request object.
83 + * @private
84 + */
85 +
86 +function getAuthorization (req) {
87 + if (!req.headers || typeof req.headers !== 'object') {
88 + throw new TypeError('argument req is required to have headers property')
89 + }
90 +
91 + return req.headers.authorization
92 +}
93 +
94 +/**
95 + * Parse basic auth to object.
96 + *
97 + * @param {string} string
98 + * @return {object}
99 + * @public
100 + */
101 +
102 +function parse (string) {
103 + if (typeof string !== 'string') {
104 + return undefined
105 + }
106 +
107 + // parse header
108 + var match = CREDENTIALS_REGEXP.exec(string)
109 +
110 + if (!match) {
111 + return undefined
112 + }
113 +
114 + // decode user pass
115 + var userPass = USER_PASS_REGEXP.exec(decodeBase64(match[1]))
116 +
117 + if (!userPass) {
118 + return undefined
119 + }
120 +
121 + // return credentials object
122 + return new Credentials(userPass[1], userPass[2])
123 +}
124 +
125 +/**
126 + * Object to represent user credentials.
127 + * @private
128 + */
129 +
130 +function Credentials (name, pass) {
131 + this.name = name
132 + this.pass = pass
133 +}
1 +{
2 + "_from": "basic-auth@~2.0.0",
3 + "_id": "basic-auth@2.0.0",
4 + "_inBundle": false,
5 + "_integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=",
6 + "_location": "/basic-auth",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "basic-auth@~2.0.0",
12 + "name": "basic-auth",
13 + "escapedName": "basic-auth",
14 + "rawSpec": "~2.0.0",
15 + "saveSpec": null,
16 + "fetchSpec": "~2.0.0"
17 + },
18 + "_requiredBy": [
19 + "/morgan"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
22 + "_shasum": "015db3f353e02e56377755f962742e8981e7bbba",
23 + "_spec": "basic-auth@~2.0.0",
24 + "_where": "/home/ubuntu/OpenSource_Project/node_modules/morgan",
25 + "bugs": {
26 + "url": "https://github.com/jshttp/basic-auth/issues"
27 + },
28 + "bundleDependencies": false,
29 + "dependencies": {
30 + "safe-buffer": "5.1.1"
31 + },
32 + "deprecated": false,
33 + "description": "node.js basic auth parser",
34 + "devDependencies": {
35 + "eslint": "3.19.0",
36 + "eslint-config-standard": "10.2.1",
37 + "eslint-plugin-import": "2.7.0",
38 + "eslint-plugin-markdown": "1.0.0-beta.6",
39 + "eslint-plugin-node": "5.1.1",
40 + "eslint-plugin-promise": "3.5.0",
41 + "eslint-plugin-standard": "3.0.1",
42 + "istanbul": "0.4.5",
43 + "mocha": "2.5.3"
44 + },
45 + "engines": {
46 + "node": ">= 0.8"
47 + },
48 + "files": [
49 + "HISTORY.md",
50 + "LICENSE",
51 + "index.js"
52 + ],
53 + "homepage": "https://github.com/jshttp/basic-auth#readme",
54 + "keywords": [
55 + "basic",
56 + "auth",
57 + "authorization",
58 + "basicauth"
59 + ],
60 + "license": "MIT",
61 + "name": "basic-auth",
62 + "repository": {
63 + "type": "git",
64 + "url": "git+https://github.com/jshttp/basic-auth.git"
65 + },
66 + "scripts": {
67 + "lint": "eslint --plugin markdown --ext js,md .",
68 + "test": "mocha --check-leaks --reporter spec --bail",
69 + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
70 + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
71 + },
72 + "version": "2.0.0"
73 +}
1 +1.4.3 / 2016-05-26
2 +==================
3 +
4 + * deps: cookie@0.3.1
5 + - perf: use for loop in parse
6 +
7 +1.4.2 / 2016-05-20
8 +==================
9 +
10 + * deps: cookie@0.2.4
11 + - perf: enable strict mode
12 + - perf: use for loop in parse
13 + - perf: use string concatination for serialization
14 +
15 +1.4.1 / 2016-01-11
16 +==================
17 +
18 + * deps: cookie@0.2.3
19 + * perf: enable strict mode
20 +
21 +1.4.0 / 2015-09-18
22 +==================
23 +
24 + * Accept array of secrets in addition to a single secret
25 + * Fix `JSONCookie` to return `undefined` for non-string arguments
26 + * Fix `signedCookie` to return `undefined` for non-string arguments
27 + * deps: cookie@0.2.2
28 +
29 +1.3.5 / 2015-05-19
30 +==================
31 +
32 + * deps: cookie@0.1.3
33 + - Slight optimizations
34 +
35 +1.3.4 / 2015-02-15
36 +==================
37 +
38 + * deps: cookie-signature@1.0.6
39 +
40 +1.3.3 / 2014-09-05
41 +==================
42 +
43 + * deps: cookie-signature@1.0.5
44 +
45 +1.3.2 / 2014-06-26
46 +==================
47 +
48 + * deps: cookie-signature@1.0.4
49 + - fix for timing attacks
50 +
51 +1.3.1 / 2014-06-17
52 +==================
53 +
54 + * actually export `signedCookie`
55 +
56 +1.3.0 / 2014-06-17
57 +==================
58 +
59 + * add `signedCookie` export for single cookie unsigning
60 +
61 +1.2.0 / 2014-06-17
62 +==================
63 +
64 + * export parsing functions
65 + * `req.cookies` and `req.signedCookies` are now plain objects
66 + * slightly faster parsing of many cookies
67 +
68 +1.1.0 / 2014-05-12
69 +==================
70 +
71 + * Support for NodeJS version 0.8
72 + * deps: cookie@0.1.2
73 + - Fix for maxAge == 0
74 + - made compat with expires field
75 + - tweak maxAge NaN error message
76 +
77 +1.0.1 / 2014-02-20
78 +==================
79 +
80 + * add missing dependencies
81 +
82 +1.0.0 / 2014-02-15
83 +==================
84 +
85 + * Genesis from `connect`
1 +(The MIT License)
2 +
3 +Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca>
4 +Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
5 +
6 +Permission is hereby granted, free of charge, to any person obtaining
7 +a copy of this software and associated documentation files (the
8 +'Software'), to deal in the Software without restriction, including
9 +without limitation the rights to use, copy, modify, merge, publish,
10 +distribute, sublicense, and/or sell copies of the Software, and to
11 +permit persons to whom the Software is furnished to do so, subject to
12 +the following conditions:
13 +
14 +The above copyright notice and this permission notice shall be
15 +included in all copies or substantial portions of the Software.
16 +
17 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
18 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +# cookie-parser
2 +
3 +[![NPM Version][npm-image]][npm-url]
4 +[![NPM Downloads][downloads-image]][downloads-url]
5 +[![Node.js Version][node-version-image]][node-version-url]
6 +[![Build Status][travis-image]][travis-url]
7 +[![Test Coverage][coveralls-image]][coveralls-url]
8 +
9 +Parse `Cookie` header and populate `req.cookies` with an object keyed by the cookie
10 +names. Optionally you may enable signed cookie support by passing a `secret` string,
11 +which assigns `req.secret` so it may be used by other middleware.
12 +
13 +## Installation
14 +
15 +```sh
16 +$ npm install cookie-parser
17 +```
18 +
19 +## API
20 +
21 +```js
22 +var express = require('express')
23 +var cookieParser = require('cookie-parser')
24 +
25 +var app = express()
26 +app.use(cookieParser())
27 +```
28 +
29 +### cookieParser(secret, options)
30 +
31 +- `secret` a string or array used for signing cookies. This is optional and if not specified, will not parse signed cookies. If a string is provided, this is used as the secret. If an array is provided, an attempt will be made to unsign the cookie with each secret in order.
32 +- `options` an object that is passed to `cookie.parse` as the second option. See [cookie](https://www.npmjs.org/package/cookie) for more information.
33 + - `decode` a function to decode the value of the cookie
34 +
35 +### cookieParser.JSONCookie(str)
36 +
37 +Parse a cookie value as a JSON cookie. This will return the parsed JSON value if it was a JSON cookie, otherwise it will return the passed value.
38 +
39 +### cookieParser.JSONCookies(cookies)
40 +
41 +Given an object, this will iterate over the keys and call `JSONCookie` on each value. This will return the same object passed in.
42 +
43 +### cookieParser.signedCookie(str, secret)
44 +
45 +Parse a cookie value as a signed cookie. This will return the parsed unsigned value if it was a signed cookie and the signature was valid, otherwise it will return the passed value.
46 +
47 +The `secret` argument can be an array or string. If a string is provided, this is used as the secret. If an array is provided, an attempt will be made to unsign the cookie with each secret in order.
48 +
49 +### cookieParser.signedCookies(cookies, secret)
50 +
51 +Given an object, this will iterate over the keys and check if any value is a signed cookie. If it is a signed cookie and the signature is valid, the key will be deleted from the object and added to the new object that is returned.
52 +
53 +The `secret` argument can be an array or string. If a string is provided, this is used as the secret. If an array is provided, an attempt will be made to unsign the cookie with each secret in order.
54 +
55 +## Example
56 +
57 +```js
58 +var express = require('express')
59 +var cookieParser = require('cookie-parser')
60 +
61 +var app = express()
62 +app.use(cookieParser())
63 +
64 +app.get('/', function(req, res) {
65 + console.log('Cookies: ', req.cookies)
66 +})
67 +
68 +app.listen(8080)
69 +
70 +// curl command that sends an HTTP request with two cookies
71 +// curl http://127.0.0.1:8080 --cookie "Cho=Kim;Greet=Hello"
72 +```
73 +
74 +### [MIT Licensed](LICENSE)
75 +
76 +[npm-image]: https://img.shields.io/npm/v/cookie-parser.svg
77 +[npm-url]: https://npmjs.org/package/cookie-parser
78 +[node-version-image]: https://img.shields.io/node/v/cookie-parser.svg
79 +[node-version-url]: https://nodejs.org/en/download
80 +[travis-image]: https://img.shields.io/travis/expressjs/cookie-parser/master.svg
81 +[travis-url]: https://travis-ci.org/expressjs/cookie-parser
82 +[coveralls-image]: https://img.shields.io/coveralls/expressjs/cookie-parser/master.svg
83 +[coveralls-url]: https://coveralls.io/r/expressjs/cookie-parser?branch=master
84 +[downloads-image]: https://img.shields.io/npm/dm/cookie-parser.svg
85 +[downloads-url]: https://npmjs.org/package/cookie-parser
1 +/*!
2 + * cookie-parser
3 + * Copyright(c) 2014 TJ Holowaychuk
4 + * Copyright(c) 2015 Douglas Christopher Wilson
5 + * MIT Licensed
6 + */
7 +
8 +'use strict';
9 +
10 +/**
11 + * Module dependencies.
12 + * @private
13 + */
14 +
15 +var cookie = require('cookie');
16 +var signature = require('cookie-signature');
17 +
18 +/**
19 + * Module exports.
20 + * @public
21 + */
22 +
23 +module.exports = cookieParser;
24 +module.exports.JSONCookie = JSONCookie;
25 +module.exports.JSONCookies = JSONCookies;
26 +module.exports.signedCookie = signedCookie;
27 +module.exports.signedCookies = signedCookies;
28 +
29 +/**
30 + * Parse Cookie header and populate `req.cookies`
31 + * with an object keyed by the cookie names.
32 + *
33 + * @param {string|array} [secret] A string (or array of strings) representing cookie signing secret(s).
34 + * @param {Object} [options]
35 + * @return {Function}
36 + * @public
37 + */
38 +
39 +function cookieParser(secret, options) {
40 + return function cookieParser(req, res, next) {
41 + if (req.cookies) {
42 + return next();
43 + }
44 +
45 + var cookies = req.headers.cookie;
46 + var secrets = !secret || Array.isArray(secret)
47 + ? (secret || [])
48 + : [secret];
49 +
50 + req.secret = secrets[0];
51 + req.cookies = Object.create(null);
52 + req.signedCookies = Object.create(null);
53 +
54 + // no cookies
55 + if (!cookies) {
56 + return next();
57 + }
58 +
59 + req.cookies = cookie.parse(cookies, options);
60 +
61 + // parse signed cookies
62 + if (secrets.length !== 0) {
63 + req.signedCookies = signedCookies(req.cookies, secrets);
64 + req.signedCookies = JSONCookies(req.signedCookies);
65 + }
66 +
67 + // parse JSON cookies
68 + req.cookies = JSONCookies(req.cookies);
69 +
70 + next();
71 + };
72 +}
73 +
74 +/**
75 + * Parse JSON cookie string.
76 + *
77 + * @param {String} str
78 + * @return {Object} Parsed object or undefined if not json cookie
79 + * @public
80 + */
81 +
82 +function JSONCookie(str) {
83 + if (typeof str !== 'string' || str.substr(0, 2) !== 'j:') {
84 + return undefined;
85 + }
86 +
87 + try {
88 + return JSON.parse(str.slice(2));
89 + } catch (err) {
90 + return undefined;
91 + }
92 +}
93 +
94 +/**
95 + * Parse JSON cookies.
96 + *
97 + * @param {Object} obj
98 + * @return {Object}
99 + * @public
100 + */
101 +
102 +function JSONCookies(obj) {
103 + var cookies = Object.keys(obj);
104 + var key;
105 + var val;
106 +
107 + for (var i = 0; i < cookies.length; i++) {
108 + key = cookies[i];
109 + val = JSONCookie(obj[key]);
110 +
111 + if (val) {
112 + obj[key] = val;
113 + }
114 + }
115 +
116 + return obj;
117 +}
118 +
119 +/**
120 + * Parse a signed cookie string, return the decoded value.
121 + *
122 + * @param {String} str signed cookie string
123 + * @param {string|array} secret
124 + * @return {String} decoded value
125 + * @public
126 + */
127 +
128 +function signedCookie(str, secret) {
129 + if (typeof str !== 'string') {
130 + return undefined;
131 + }
132 +
133 + if (str.substr(0, 2) !== 's:') {
134 + return str;
135 + }
136 +
137 + var secrets = !secret || Array.isArray(secret)
138 + ? (secret || [])
139 + : [secret];
140 +
141 + for (var i = 0; i < secrets.length; i++) {
142 + var val = signature.unsign(str.slice(2), secrets[i]);
143 +
144 + if (val !== false) {
145 + return val;
146 + }
147 + }
148 +
149 + return false;
150 +}
151 +
152 +/**
153 + * Parse signed cookies, returning an object containing the decoded key/value
154 + * pairs, while removing the signed key from obj.
155 + *
156 + * @param {Object} obj
157 + * @param {string|array} secret
158 + * @return {Object}
159 + * @public
160 + */
161 +
162 +function signedCookies(obj, secret) {
163 + var cookies = Object.keys(obj);
164 + var dec;
165 + var key;
166 + var ret = Object.create(null);
167 + var val;
168 +
169 + for (var i = 0; i < cookies.length; i++) {
170 + key = cookies[i];
171 + val = obj[key];
172 + dec = signedCookie(val, secret);
173 +
174 + if (val !== dec) {
175 + ret[key] = dec;
176 + delete obj[key];
177 + }
178 + }
179 +
180 + return ret;
181 +}
1 +{
2 + "_from": "cookie-parser@~1.4.3",
3 + "_id": "cookie-parser@1.4.3",
4 + "_inBundle": false,
5 + "_integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=",
6 + "_location": "/cookie-parser",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "cookie-parser@~1.4.3",
12 + "name": "cookie-parser",
13 + "escapedName": "cookie-parser",
14 + "rawSpec": "~1.4.3",
15 + "saveSpec": null,
16 + "fetchSpec": "~1.4.3"
17 + },
18 + "_requiredBy": [
19 + "/"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz",
22 + "_shasum": "0fe31fa19d000b95f4aadf1f53fdc2b8a203baa5",
23 + "_spec": "cookie-parser@~1.4.3",
24 + "_where": "/home/ubuntu/OpenSource_Project",
25 + "author": {
26 + "name": "TJ Holowaychuk",
27 + "email": "tj@vision-media.ca",
28 + "url": "http://tjholowaychuk.com"
29 + },
30 + "bugs": {
31 + "url": "https://github.com/expressjs/cookie-parser/issues"
32 + },
33 + "bundleDependencies": false,
34 + "contributors": [
35 + {
36 + "name": "Douglas Christopher Wilson",
37 + "email": "doug@somethingdoug.com"
38 + }
39 + ],
40 + "dependencies": {
41 + "cookie": "0.3.1",
42 + "cookie-signature": "1.0.6"
43 + },
44 + "deprecated": false,
45 + "description": "cookie parsing with signatures",
46 + "devDependencies": {
47 + "istanbul": "0.4.3",
48 + "mocha": "2.5.3",
49 + "supertest": "1.1.0"
50 + },
51 + "engines": {
52 + "node": ">= 0.8.0"
53 + },
54 + "files": [
55 + "LICENSE",
56 + "HISTORY.md",
57 + "index.js"
58 + ],
59 + "homepage": "https://github.com/expressjs/cookie-parser#readme",
60 + "keywords": [
61 + "cookie",
62 + "middleware"
63 + ],
64 + "license": "MIT",
65 + "name": "cookie-parser",
66 + "repository": {
67 + "type": "git",
68 + "url": "git+https://github.com/expressjs/cookie-parser.git"
69 + },
70 + "scripts": {
71 + "test": "mocha --reporter spec --bail --check-leaks test/",
72 + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
73 + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
74 + },
75 + "version": "1.4.3"
76 +}
1 +var fs = require('fs');
2 +var execSync = require('child_process').execSync;
3 +var exec = function (cmd) {
4 + execSync(cmd, {stdio: 'inherit'});
5 +};
6 +
7 +/* global jake, task, desc, publishTask */
8 +
9 +task('build', ['lint', 'clean', 'browserify', 'minify'], function () {
10 + console.log('Build completed.');
11 +});
12 +
13 +desc('Cleans browerified/minified files and package files');
14 +task('clean', ['clobber'], function () {
15 + jake.rmRf('./ejs.js');
16 + jake.rmRf('./ejs.min.js');
17 + console.log('Cleaned up compiled files.');
18 +});
19 +
20 +desc('Lints the source code');
21 +task('lint', function () {
22 + exec('./node_modules/.bin/eslint \"**/*.js\" Jakefile');
23 + console.log('Linting completed.');
24 +});
25 +
26 +task('browserify', function () {
27 + exec('./node_modules/browserify/bin/cmd.js --standalone ejs lib/ejs.js > ejs.js');
28 + console.log('Browserification completed.');
29 +});
30 +
31 +task('minify', function () {
32 + exec('./node_modules/uglify-js/bin/uglifyjs ejs.js > ejs.min.js');
33 + console.log('Minification completed.');
34 +});
35 +
36 +task('doc', function (dev) {
37 + jake.rmRf('out');
38 + var p = dev ? '-p' : '';
39 + exec('./node_modules/.bin/jsdoc ' + p + ' -c jsdoc.json lib/* docs/jsdoc/*');
40 + console.log('Documentation generated.');
41 +});
42 +
43 +task('docPublish', ['doc'], function () {
44 + fs.writeFileSync('out/CNAME', 'api.ejs.co');
45 + console.log('Pushing docs to gh-pages...');
46 + exec('./node_modules/.bin/git-directory-deploy --directory out/');
47 + console.log('Docs published to gh-pages.');
48 +});
49 +
50 +task('test', ['lint'], function () {
51 + exec('./node_modules/.bin/mocha');
52 +});
53 +
54 +publishTask('ejs', ['build'], function () {
55 + this.packageFiles.include([
56 + 'Jakefile',
57 + 'README.md',
58 + 'LICENSE',
59 + 'package.json',
60 + 'ejs.js',
61 + 'ejs.min.js',
62 + 'lib/**'
63 + ]);
64 +});
65 +
66 +jake.Task.publish.on('complete', function () {
67 + console.log('Updating hosted docs...');
68 + console.log('If this fails, run jake docPublish to re-try.');
69 + jake.Task.docPublish.invoke();
70 +});
1 +
2 + Apache License
3 + Version 2.0, January 2004
4 + http://www.apache.org/licenses/
5 +
6 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 +
8 + 1. Definitions.
9 +
10 + "License" shall mean the terms and conditions for use, reproduction,
11 + and distribution as defined by Sections 1 through 9 of this document.
12 +
13 + "Licensor" shall mean the copyright owner or entity authorized by
14 + the copyright owner that is granting the License.
15 +
16 + "Legal Entity" shall mean the union of the acting entity and all
17 + other entities that control, are controlled by, or are under common
18 + control with that entity. For the purposes of this definition,
19 + "control" means (i) the power, direct or indirect, to cause the
20 + direction or management of such entity, whether by contract or
21 + otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 + outstanding shares, or (iii) beneficial ownership of such entity.
23 +
24 + "You" (or "Your") shall mean an individual or Legal Entity
25 + exercising permissions granted by this License.
26 +
27 + "Source" form shall mean the preferred form for making modifications,
28 + including but not limited to software source code, documentation
29 + source, and configuration files.
30 +
31 + "Object" form shall mean any form resulting from mechanical
32 + transformation or translation of a Source form, including but
33 + not limited to compiled object code, generated documentation,
34 + and conversions to other media types.
35 +
36 + "Work" shall mean the work of authorship, whether in Source or
37 + Object form, made available under the License, as indicated by a
38 + copyright notice that is included in or attached to the work
39 + (an example is provided in the Appendix below).
40 +
41 + "Derivative Works" shall mean any work, whether in Source or Object
42 + form, that is based on (or derived from) the Work and for which the
43 + editorial revisions, annotations, elaborations, or other modifications
44 + represent, as a whole, an original work of authorship. For the purposes
45 + of this License, Derivative Works shall not include works that remain
46 + separable from, or merely link (or bind by name) to the interfaces of,
47 + the Work and Derivative Works thereof.
48 +
49 + "Contribution" shall mean any work of authorship, including
50 + the original version of the Work and any modifications or additions
51 + to that Work or Derivative Works thereof, that is intentionally
52 + submitted to Licensor for inclusion in the Work by the copyright owner
53 + or by an individual or Legal Entity authorized to submit on behalf of
54 + the copyright owner. For the purposes of this definition, "submitted"
55 + means any form of electronic, verbal, or written communication sent
56 + to the Licensor or its representatives, including but not limited to
57 + communication on electronic mailing lists, source code control systems,
58 + and issue tracking systems that are managed by, or on behalf of, the
59 + Licensor for the purpose of discussing and improving the Work, but
60 + excluding communication that is conspicuously marked or otherwise
61 + designated in writing by the copyright owner as "Not a Contribution."
62 +
63 + "Contributor" shall mean Licensor and any individual or Legal Entity
64 + on behalf of whom a Contribution has been received by Licensor and
65 + subsequently incorporated within the Work.
66 +
67 + 2. Grant of Copyright License. Subject to the terms and conditions of
68 + this License, each Contributor hereby grants to You a perpetual,
69 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 + copyright license to reproduce, prepare Derivative Works of,
71 + publicly display, publicly perform, sublicense, and distribute the
72 + Work and such Derivative Works in Source or Object form.
73 +
74 + 3. Grant of Patent License. Subject to the terms and conditions of
75 + this License, each Contributor hereby grants to You a perpetual,
76 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 + (except as stated in this section) patent license to make, have made,
78 + use, offer to sell, sell, import, and otherwise transfer the Work,
79 + where such license applies only to those patent claims licensable
80 + by such Contributor that are necessarily infringed by their
81 + Contribution(s) alone or by combination of their Contribution(s)
82 + with the Work to which such Contribution(s) was submitted. If You
83 + institute patent litigation against any entity (including a
84 + cross-claim or counterclaim in a lawsuit) alleging that the Work
85 + or a Contribution incorporated within the Work constitutes direct
86 + or contributory patent infringement, then any patent licenses
87 + granted to You under this License for that Work shall terminate
88 + as of the date such litigation is filed.
89 +
90 + 4. Redistribution. You may reproduce and distribute copies of the
91 + Work or Derivative Works thereof in any medium, with or without
92 + modifications, and in Source or Object form, provided that You
93 + meet the following conditions:
94 +
95 + (a) You must give any other recipients of the Work or
96 + Derivative Works a copy of this License; and
97 +
98 + (b) You must cause any modified files to carry prominent notices
99 + stating that You changed the files; and
100 +
101 + (c) You must retain, in the Source form of any Derivative Works
102 + that You distribute, all copyright, patent, trademark, and
103 + attribution notices from the Source form of the Work,
104 + excluding those notices that do not pertain to any part of
105 + the Derivative Works; and
106 +
107 + (d) If the Work includes a "NOTICE" text file as part of its
108 + distribution, then any Derivative Works that You distribute must
109 + include a readable copy of the attribution notices contained
110 + within such NOTICE file, excluding those notices that do not
111 + pertain to any part of the Derivative Works, in at least one
112 + of the following places: within a NOTICE text file distributed
113 + as part of the Derivative Works; within the Source form or
114 + documentation, if provided along with the Derivative Works; or,
115 + within a display generated by the Derivative Works, if and
116 + wherever such third-party notices normally appear. The contents
117 + of the NOTICE file are for informational purposes only and
118 + do not modify the License. You may add Your own attribution
119 + notices within Derivative Works that You distribute, alongside
120 + or as an addendum to the NOTICE text from the Work, provided
121 + that such additional attribution notices cannot be construed
122 + as modifying the License.
123 +
124 + You may add Your own copyright statement to Your modifications and
125 + may provide additional or different license terms and conditions
126 + for use, reproduction, or distribution of Your modifications, or
127 + for any such Derivative Works as a whole, provided Your use,
128 + reproduction, and distribution of the Work otherwise complies with
129 + the conditions stated in this License.
130 +
131 + 5. Submission of Contributions. Unless You explicitly state otherwise,
132 + any Contribution intentionally submitted for inclusion in the Work
133 + by You to the Licensor shall be under the terms and conditions of
134 + this License, without any additional terms or conditions.
135 + Notwithstanding the above, nothing herein shall supersede or modify
136 + the terms of any separate license agreement you may have executed
137 + with Licensor regarding such Contributions.
138 +
139 + 6. Trademarks. This License does not grant permission to use the trade
140 + names, trademarks, service marks, or product names of the Licensor,
141 + except as required for reasonable and customary use in describing the
142 + origin of the Work and reproducing the content of the NOTICE file.
143 +
144 + 7. Disclaimer of Warranty. Unless required by applicable law or
145 + agreed to in writing, Licensor provides the Work (and each
146 + Contributor provides its Contributions) on an "AS IS" BASIS,
147 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 + implied, including, without limitation, any warranties or conditions
149 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 + PARTICULAR PURPOSE. You are solely responsible for determining the
151 + appropriateness of using or redistributing the Work and assume any
152 + risks associated with Your exercise of permissions under this License.
153 +
154 + 8. Limitation of Liability. In no event and under no legal theory,
155 + whether in tort (including negligence), contract, or otherwise,
156 + unless required by applicable law (such as deliberate and grossly
157 + negligent acts) or agreed to in writing, shall any Contributor be
158 + liable to You for damages, including any direct, indirect, special,
159 + incidental, or consequential damages of any character arising as a
160 + result of this License or out of the use or inability to use the
161 + Work (including but not limited to damages for loss of goodwill,
162 + work stoppage, computer failure or malfunction, or any and all
163 + other commercial damages or losses), even if such Contributor
164 + has been advised of the possibility of such damages.
165 +
166 + 9. Accepting Warranty or Additional Liability. While redistributing
167 + the Work or Derivative Works thereof, You may choose to offer,
168 + and charge a fee for, acceptance of support, warranty, indemnity,
169 + or other liability obligations and/or rights consistent with this
170 + License. However, in accepting such obligations, You may act only
171 + on Your own behalf and on Your sole responsibility, not on behalf
172 + of any other Contributor, and only if You agree to indemnify,
173 + defend, and hold each Contributor harmless for any liability
174 + incurred by, or claims asserted against, such Contributor by reason
175 + of your accepting any such warranty or additional liability.
176 +
177 + END OF TERMS AND CONDITIONS
178 +
179 + APPENDIX: How to apply the Apache License to your work.
180 +
181 + To apply the Apache License to your work, attach the following
182 + boilerplate notice, with the fields enclosed by brackets "[]"
183 + replaced with your own identifying information. (Don't include
184 + the brackets!) The text should be enclosed in the appropriate
185 + comment syntax for the file format. We also recommend that a
186 + file or class name and description of purpose be included on the
187 + same "printed page" as the copyright notice for easier
188 + identification within third-party archives.
189 +
190 + Copyright [yyyy] [name of copyright owner]
191 +
192 + Licensed under the Apache License, Version 2.0 (the "License");
193 + you may not use this file except in compliance with the License.
194 + You may obtain a copy of the License at
195 +
196 + http://www.apache.org/licenses/LICENSE-2.0
197 +
198 + Unless required by applicable law or agreed to in writing, software
199 + distributed under the License is distributed on an "AS IS" BASIS,
200 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 + See the License for the specific language governing permissions and
202 + limitations under the License.
1 +# EJS
2 +
3 +Embedded JavaScript templates
4 +
5 +[![Build Status](https://img.shields.io/travis/mde/ejs/master.svg?style=flat)](https://travis-ci.org/mde/ejs)
6 +[![Developing Dependencies](https://img.shields.io/david/dev/mde/ejs.svg?style=flat)](https://david-dm.org/mde/ejs?type=dev)
7 +[![Known Vulnerabilities](https://snyk.io/test/npm/ejs/badge.svg?style=flat-square)](https://snyk.io/test/npm/ejs)
8 +
9 +## Installation
10 +
11 +```bash
12 +$ npm install ejs
13 +```
14 +
15 +## Features
16 +
17 + * Control flow with `<% %>`
18 + * Escaped output with `<%= %>` (escape function configurable)
19 + * Unescaped raw output with `<%- %>`
20 + * Newline-trim mode ('newline slurping') with `-%>` ending tag
21 + * Whitespace-trim mode (slurp all whitespace) for control flow with `<%_ _%>`
22 + * Custom delimiters (e.g., use `<? ?>` instead of `<% %>`)
23 + * Includes
24 + * Client-side support
25 + * Static caching of intermediate JavaScript
26 + * Static caching of templates
27 + * Complies with the [Express](http://expressjs.com) view system
28 +
29 +## Example
30 +
31 +```html
32 +<% if (user) { %>
33 + <h2><%= user.name %></h2>
34 +<% } %>
35 +```
36 +
37 +Try EJS online at: https://ionicabizau.github.io/ejs-playground/.
38 +
39 +## Usage
40 +
41 +```javascript
42 +var template = ejs.compile(str, options);
43 +template(data);
44 +// => Rendered HTML string
45 +
46 +ejs.render(str, data, options);
47 +// => Rendered HTML string
48 +
49 +ejs.renderFile(filename, data, options, function(err, str){
50 + // str => Rendered HTML string
51 +});
52 +```
53 +
54 +It is also possible to use `ejs.render(dataAndOptions);` where you pass
55 +everything in a single object. In that case, you'll end up with local variables
56 +for all the passed options. However, be aware that your code could break if we
57 +add an option with the same name as one of your data object's properties.
58 +Therefore, we do not recommend using this shortcut.
59 +
60 +## Options
61 +
62 + - `cache` Compiled functions are cached, requires `filename`
63 + - `filename` The name of the file being rendered. Not required if you
64 + are using `renderFile()`. Used by `cache` to key caches, and for includes.
65 + - `root` Set project root for includes with an absolute path (/file.ejs).
66 + - `context` Function execution context
67 + - `compileDebug` When `false` no debug instrumentation is compiled
68 + - `client` When `true`, compiles a function that can be rendered
69 + in the browser without needing to load the EJS Runtime
70 + ([ejs.min.js](https://github.com/mde/ejs/releases/latest)).
71 + - `delimiter` Character to use with angle brackets for open/close
72 + - `debug` Output generated function body
73 + - `strict` When set to `true`, generated function is in strict mode
74 + - `_with` Whether or not to use `with() {}` constructs. If `false` then the locals will be stored in the `locals` object. Set to `false` in strict mode.
75 + - `localsName` Name to use for the object storing local variables when not using `with` Defaults to `locals`
76 + - `rmWhitespace` Remove all safe-to-remove whitespace, including leading
77 + and trailing whitespace. It also enables a safer version of `-%>` line
78 + slurping for all scriptlet tags (it does not strip new lines of tags in
79 + the middle of a line).
80 + - `escape` The escaping function used with `<%=` construct. It is
81 + used in rendering and is `.toString()`ed in the generation of client functions. (By default escapes XML).
82 +
83 +This project uses [JSDoc](http://usejsdoc.org/). For the full public API
84 +documentation, clone the repository and run `npm run doc`. This will run JSDoc
85 +with the proper options and output the documentation to `out/`. If you want
86 +the both the public & private API docs, run `npm run devdoc` instead.
87 +
88 +## Tags
89 +
90 + - `<%` 'Scriptlet' tag, for control-flow, no output
91 + - `<%_` 'Whitespace Slurping' Scriptlet tag, strips all whitespace before it
92 + - `<%=` Outputs the value into the template (escaped)
93 + - `<%-` Outputs the unescaped value into the template
94 + - `<%#` Comment tag, no execution, no output
95 + - `<%%` Outputs a literal '<%'
96 + - `%%>` Outputs a literal '%>'
97 + - `%>` Plain ending tag
98 + - `-%>` Trim-mode ('newline slurp') tag, trims following newline
99 + - `_%>` 'Whitespace Slurping' ending tag, removes all whitespace after it
100 +
101 +For the full syntax documentation, please see [docs/syntax.md](https://github.com/mde/ejs/blob/master/docs/syntax.md).
102 +
103 +## Includes
104 +
105 +Includes either have to be an absolute path, or, if not, are assumed as
106 +relative to the template with the `include` call. For example if you are
107 +including `./views/user/show.ejs` from `./views/users.ejs` you would
108 +use `<%- include('user/show') %>`.
109 +
110 +You must specify the `filename` option for the template with the `include`
111 +call unless you are using `renderFile()`.
112 +
113 +You'll likely want to use the raw output tag (`<%-`) with your include to avoid
114 +double-escaping the HTML output.
115 +
116 +```html
117 +<ul>
118 + <% users.forEach(function(user){ %>
119 + <%- include('user/show', {user: user}) %>
120 + <% }); %>
121 +</ul>
122 +```
123 +
124 +Includes are inserted at runtime, so you can use variables for the path in the
125 +`include` call (for example `<%- include(somePath) %>`). Variables in your
126 +top-level data object are available to all your includes, but local variables
127 +need to be passed down.
128 +
129 +NOTE: Include preprocessor directives (`<% include user/show %>`) are
130 +still supported.
131 +
132 +## Custom delimiters
133 +
134 +Custom delimiters can be applied on a per-template basis, or globally:
135 +
136 +```javascript
137 +var ejs = require('ejs'),
138 + users = ['geddy', 'neil', 'alex'];
139 +
140 +// Just one template
141 +ejs.render('<?= users.join(" | "); ?>', {users: users}, {delimiter: '?'});
142 +// => 'geddy | neil | alex'
143 +
144 +// Or globally
145 +ejs.delimiter = '$';
146 +ejs.render('<$= users.join(" | "); $>', {users: users});
147 +// => 'geddy | neil | alex'
148 +```
149 +
150 +## Caching
151 +
152 +EJS ships with a basic in-process cache for caching the intermediate JavaScript
153 +functions used to render templates. It's easy to plug in LRU caching using
154 +Node's `lru-cache` library:
155 +
156 +```javascript
157 +var ejs = require('ejs')
158 + , LRU = require('lru-cache');
159 +ejs.cache = LRU(100); // LRU cache with 100-item limit
160 +```
161 +
162 +If you want to clear the EJS cache, call `ejs.clearCache`. If you're using the
163 +LRU cache and need a different limit, simple reset `ejs.cache` to a new instance
164 +of the LRU.
165 +
166 +## Custom FileLoader
167 +
168 +The default file loader is `fs.readFileSync`, if you want to customize it, you can set ejs.fileLoader.
169 +
170 +```javascript
171 +var ejs = require('ejs');
172 +var myFileLoad = function (filePath) {
173 + return 'myFileLoad: ' + fs.readFileSync(filePath);
174 +};
175 +
176 +ejs.fileLoader = myFileLoad;
177 +```
178 +
179 +With this feature, you can preprocess the template before reading it.
180 +
181 +## Layouts
182 +
183 +EJS does not specifically support blocks, but layouts can be implemented by
184 +including headers and footers, like so:
185 +
186 +
187 +```html
188 +<%- include('header') -%>
189 +<h1>
190 + Title
191 +</h1>
192 +<p>
193 + My page
194 +</p>
195 +<%- include('footer') -%>
196 +```
197 +
198 +## Client-side support
199 +
200 +Go to the [Latest Release](https://github.com/mde/ejs/releases/latest), download
201 +`./ejs.js` or `./ejs.min.js`. Alternately, you can compile it yourself by cloning
202 +the repository and running `jake build` (or `$(npm bin)/jake build` if jake is
203 +not installed globally).
204 +
205 +Include one of these files on your page, and `ejs` should be available globally.
206 +
207 +### Example
208 +
209 +```html
210 +<div id="output"></div>
211 +<script src="ejs.min.js"></script>
212 +<script>
213 + var people = ['geddy', 'neil', 'alex'],
214 + html = ejs.render('<%= people.join(", "); %>', {people: people});
215 + // With jQuery:
216 + $('#output').html(html);
217 + // Vanilla JS:
218 + document.getElementById('output').innerHTML = html;
219 +</script>
220 +```
221 +
222 +### Caveats
223 +
224 +Most of EJS will work as expected; however, there are a few things to note:
225 +
226 +1. Obviously, since you do not have access to the filesystem, `ejs.renderFile()` won't work.
227 +2. For the same reason, `include`s do not work unless you use an `IncludeCallback`. Here is an example:
228 + ```javascript
229 + var str = "Hello <%= include('file', {person: 'John'}); %>",
230 + fn = ejs.compile(str, {client: true});
231 +
232 + fn(data, null, function(path, d){ // IncludeCallback
233 + // path -> 'file'
234 + // d -> {person: 'John'}
235 + // Put your code here
236 + // Return the contents of file as a string
237 + }); // returns rendered string
238 + ```
239 +
240 +## Related projects
241 +
242 +There are a number of implementations of EJS:
243 +
244 + * TJ's implementation, the v1 of this library: https://github.com/tj/ejs
245 + * Jupiter Consulting's EJS: http://www.embeddedjs.com/
246 + * EJS Embedded JavaScript Framework on Google Code: https://code.google.com/p/embeddedjavascript/
247 + * Sam Stephenson's Ruby implementation: https://rubygems.org/gems/ejs
248 + * Erubis, an ERB implementation which also runs JavaScript: http://www.kuwata-lab.com/erubis/users-guide.04.html#lang-javascript
249 +
250 +## License
251 +
252 +Licensed under the Apache License, Version 2.0
253 +(<http://www.apache.org/licenses/LICENSE-2.0>)
254 +
255 +- - -
256 +EJS Embedded JavaScript templates copyright 2112
257 +mde@fleegix.org.
1 +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ejs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2 +/*
3 + * EJS Embedded JavaScript templates
4 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
5 + *
6 + * Licensed under the Apache License, Version 2.0 (the "License");
7 + * you may not use this file except in compliance with the License.
8 + * You may obtain a copy of the License at
9 + *
10 + * http://www.apache.org/licenses/LICENSE-2.0
11 + *
12 + * Unless required by applicable law or agreed to in writing, software
13 + * distributed under the License is distributed on an "AS IS" BASIS,
14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 + * See the License for the specific language governing permissions and
16 + * limitations under the License.
17 + *
18 +*/
19 +
20 +'use strict';
21 +
22 +/**
23 + * @file Embedded JavaScript templating engine. {@link http://ejs.co}
24 + * @author Matthew Eernisse <mde@fleegix.org>
25 + * @author Tiancheng "Timothy" Gu <timothygu99@gmail.com>
26 + * @project EJS
27 + * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0}
28 + */
29 +
30 +/**
31 + * EJS internal functions.
32 + *
33 + * Technically this "module" lies in the same file as {@link module:ejs}, for
34 + * the sake of organization all the private functions re grouped into this
35 + * module.
36 + *
37 + * @module ejs-internal
38 + * @private
39 + */
40 +
41 +/**
42 + * Embedded JavaScript templating engine.
43 + *
44 + * @module ejs
45 + * @public
46 + */
47 +
48 +var fs = require('fs');
49 +var path = require('path');
50 +var utils = require('./utils');
51 +
52 +var scopeOptionWarned = false;
53 +var _VERSION_STRING = require('../package.json').version;
54 +var _DEFAULT_DELIMITER = '%';
55 +var _DEFAULT_LOCALS_NAME = 'locals';
56 +var _NAME = 'ejs';
57 +var _REGEX_STRING = '(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)';
58 +var _OPTS = ['delimiter', 'scope', 'context', 'debug', 'compileDebug',
59 + 'client', '_with', 'rmWhitespace', 'strict', 'filename'];
60 +// We don't allow 'cache' option to be passed in the data obj
61 +// for the normal `render` call, but this is where Express puts it
62 +// so we make an exception for `renderFile`
63 +var _OPTS_EXPRESS = _OPTS.concat('cache');
64 +var _BOM = /^\uFEFF/;
65 +
66 +/**
67 + * EJS template function cache. This can be a LRU object from lru-cache NPM
68 + * module. By default, it is {@link module:utils.cache}, a simple in-process
69 + * cache that grows continuously.
70 + *
71 + * @type {Cache}
72 + */
73 +
74 +exports.cache = utils.cache;
75 +
76 +/**
77 + * Custom file loader. Useful for template preprocessing or restricting access
78 + * to a certain part of the filesystem.
79 + *
80 + * @type {fileLoader}
81 + */
82 +
83 +exports.fileLoader = fs.readFileSync;
84 +
85 +/**
86 + * Name of the object containing the locals.
87 + *
88 + * This variable is overridden by {@link Options}`.localsName` if it is not
89 + * `undefined`.
90 + *
91 + * @type {String}
92 + * @public
93 + */
94 +
95 +exports.localsName = _DEFAULT_LOCALS_NAME;
96 +
97 +/**
98 + * Get the path to the included file from the parent file path and the
99 + * specified path.
100 + *
101 + * @param {String} name specified path
102 + * @param {String} filename parent file path
103 + * @param {Boolean} isDir parent file path whether is directory
104 + * @return {String}
105 + */
106 +exports.resolveInclude = function(name, filename, isDir) {
107 + var dirname = path.dirname;
108 + var extname = path.extname;
109 + var resolve = path.resolve;
110 + var includePath = resolve(isDir ? filename : dirname(filename), name);
111 + var ext = extname(name);
112 + if (!ext) {
113 + includePath += '.ejs';
114 + }
115 + return includePath;
116 +};
117 +
118 +/**
119 + * Get the path to the included file by Options
120 + *
121 + * @param {String} path specified path
122 + * @param {Options} options compilation options
123 + * @return {String}
124 + */
125 +function getIncludePath(path, options) {
126 + var includePath;
127 + var filePath;
128 + var views = options.views;
129 +
130 + // Abs path
131 + if (path.charAt(0) == '/') {
132 + includePath = exports.resolveInclude(path.replace(/^\/*/,''), options.root || '/', true);
133 + }
134 + // Relative paths
135 + else {
136 + // Look relative to a passed filename first
137 + if (options.filename) {
138 + filePath = exports.resolveInclude(path, options.filename);
139 + if (fs.existsSync(filePath)) {
140 + includePath = filePath;
141 + }
142 + }
143 + // Then look in any views directories
144 + if (!includePath) {
145 + if (Array.isArray(views) && views.some(function (v) {
146 + filePath = exports.resolveInclude(path, v, true);
147 + return fs.existsSync(filePath);
148 + })) {
149 + includePath = filePath;
150 + }
151 + }
152 + if (!includePath) {
153 + throw new Error('Could not find include include file.');
154 + }
155 + }
156 + return includePath;
157 +}
158 +
159 +/**
160 + * Get the template from a string or a file, either compiled on-the-fly or
161 + * read from cache (if enabled), and cache the template if needed.
162 + *
163 + * If `template` is not set, the file specified in `options.filename` will be
164 + * read.
165 + *
166 + * If `options.cache` is true, this function reads the file from
167 + * `options.filename` so it must be set prior to calling this function.
168 + *
169 + * @memberof module:ejs-internal
170 + * @param {Options} options compilation options
171 + * @param {String} [template] template source
172 + * @return {(TemplateFunction|ClientFunction)}
173 + * Depending on the value of `options.client`, either type might be returned.
174 + * @static
175 + */
176 +
177 +function handleCache(options, template) {
178 + var func;
179 + var filename = options.filename;
180 + var hasTemplate = arguments.length > 1;
181 +
182 + if (options.cache) {
183 + if (!filename) {
184 + throw new Error('cache option requires a filename');
185 + }
186 + func = exports.cache.get(filename);
187 + if (func) {
188 + return func;
189 + }
190 + if (!hasTemplate) {
191 + template = fileLoader(filename).toString().replace(_BOM, '');
192 + }
193 + }
194 + else if (!hasTemplate) {
195 + // istanbul ignore if: should not happen at all
196 + if (!filename) {
197 + throw new Error('Internal EJS error: no file name or template '
198 + + 'provided');
199 + }
200 + template = fileLoader(filename).toString().replace(_BOM, '');
201 + }
202 + func = exports.compile(template, options);
203 + if (options.cache) {
204 + exports.cache.set(filename, func);
205 + }
206 + return func;
207 +}
208 +
209 +/**
210 + * Try calling handleCache with the given options and data and call the
211 + * callback with the result. If an error occurs, call the callback with
212 + * the error. Used by renderFile().
213 + *
214 + * @memberof module:ejs-internal
215 + * @param {Options} options compilation options
216 + * @param {Object} data template data
217 + * @param {RenderFileCallback} cb callback
218 + * @static
219 + */
220 +
221 +function tryHandleCache(options, data, cb) {
222 + var result;
223 + try {
224 + result = handleCache(options)(data);
225 + }
226 + catch (err) {
227 + return cb(err);
228 + }
229 + return cb(null, result);
230 +}
231 +
232 +/**
233 + * fileLoader is independent
234 + *
235 + * @param {String} filePath ejs file path.
236 + * @return {String} The contents of the specified file.
237 + * @static
238 + */
239 +
240 +function fileLoader(filePath){
241 + return exports.fileLoader(filePath);
242 +}
243 +
244 +/**
245 + * Get the template function.
246 + *
247 + * If `options.cache` is `true`, then the template is cached.
248 + *
249 + * @memberof module:ejs-internal
250 + * @param {String} path path for the specified file
251 + * @param {Options} options compilation options
252 + * @return {(TemplateFunction|ClientFunction)}
253 + * Depending on the value of `options.client`, either type might be returned
254 + * @static
255 + */
256 +
257 +function includeFile(path, options) {
258 + var opts = utils.shallowCopy({}, options);
259 + opts.filename = getIncludePath(path, opts);
260 + return handleCache(opts);
261 +}
262 +
263 +/**
264 + * Get the JavaScript source of an included file.
265 + *
266 + * @memberof module:ejs-internal
267 + * @param {String} path path for the specified file
268 + * @param {Options} options compilation options
269 + * @return {Object}
270 + * @static
271 + */
272 +
273 +function includeSource(path, options) {
274 + var opts = utils.shallowCopy({}, options);
275 + var includePath;
276 + var template;
277 + includePath = getIncludePath(path, opts);
278 + template = fileLoader(includePath).toString().replace(_BOM, '');
279 + opts.filename = includePath;
280 + var templ = new Template(template, opts);
281 + templ.generateSource();
282 + return {
283 + source: templ.source,
284 + filename: includePath,
285 + template: template
286 + };
287 +}
288 +
289 +/**
290 + * Re-throw the given `err` in context to the `str` of ejs, `filename`, and
291 + * `lineno`.
292 + *
293 + * @implements RethrowCallback
294 + * @memberof module:ejs-internal
295 + * @param {Error} err Error object
296 + * @param {String} str EJS source
297 + * @param {String} filename file name of the EJS file
298 + * @param {String} lineno line number of the error
299 + * @static
300 + */
301 +
302 +function rethrow(err, str, flnm, lineno, esc){
303 + var lines = str.split('\n');
304 + var start = Math.max(lineno - 3, 0);
305 + var end = Math.min(lines.length, lineno + 3);
306 + var filename = esc(flnm); // eslint-disable-line
307 + // Error context
308 + var context = lines.slice(start, end).map(function (line, i){
309 + var curr = i + start + 1;
310 + return (curr == lineno ? ' >> ' : ' ')
311 + + curr
312 + + '| '
313 + + line;
314 + }).join('\n');
315 +
316 + // Alter exception message
317 + err.path = filename;
318 + err.message = (filename || 'ejs') + ':'
319 + + lineno + '\n'
320 + + context + '\n\n'
321 + + err.message;
322 +
323 + throw err;
324 +}
325 +
326 +function stripSemi(str){
327 + return str.replace(/;(\s*$)/, '$1');
328 +}
329 +
330 +/**
331 + * Compile the given `str` of ejs into a template function.
332 + *
333 + * @param {String} template EJS template
334 + *
335 + * @param {Options} opts compilation options
336 + *
337 + * @return {(TemplateFunction|ClientFunction)}
338 + * Depending on the value of `opts.client`, either type might be returned.
339 + * @public
340 + */
341 +
342 +exports.compile = function compile(template, opts) {
343 + var templ;
344 +
345 + // v1 compat
346 + // 'scope' is 'context'
347 + // FIXME: Remove this in a future version
348 + if (opts && opts.scope) {
349 + if (!scopeOptionWarned){
350 + console.warn('`scope` option is deprecated and will be removed in EJS 3');
351 + scopeOptionWarned = true;
352 + }
353 + if (!opts.context) {
354 + opts.context = opts.scope;
355 + }
356 + delete opts.scope;
357 + }
358 + templ = new Template(template, opts);
359 + return templ.compile();
360 +};
361 +
362 +/**
363 + * Render the given `template` of ejs.
364 + *
365 + * If you would like to include options but not data, you need to explicitly
366 + * call this function with `data` being an empty object or `null`.
367 + *
368 + * @param {String} template EJS template
369 + * @param {Object} [data={}] template data
370 + * @param {Options} [opts={}] compilation and rendering options
371 + * @return {String}
372 + * @public
373 + */
374 +
375 +exports.render = function (template, d, o) {
376 + var data = d || {};
377 + var opts = o || {};
378 +
379 + // No options object -- if there are optiony names
380 + // in the data, copy them to options
381 + if (arguments.length == 2) {
382 + utils.shallowCopyFromList(opts, data, _OPTS);
383 + }
384 +
385 + return handleCache(opts, template)(data);
386 +};
387 +
388 +/**
389 + * Render an EJS file at the given `path` and callback `cb(err, str)`.
390 + *
391 + * If you would like to include options but not data, you need to explicitly
392 + * call this function with `data` being an empty object or `null`.
393 + *
394 + * @param {String} path path to the EJS file
395 + * @param {Object} [data={}] template data
396 + * @param {Options} [opts={}] compilation and rendering options
397 + * @param {RenderFileCallback} cb callback
398 + * @public
399 + */
400 +
401 +exports.renderFile = function () {
402 + var filename = arguments[0];
403 + var cb = arguments[arguments.length - 1];
404 + var opts = {filename: filename};
405 + var data;
406 +
407 + if (arguments.length > 2) {
408 + data = arguments[1];
409 +
410 + // No options object -- if there are optiony names
411 + // in the data, copy them to options
412 + if (arguments.length === 3) {
413 + // Express 4
414 + if (data.settings) {
415 + if (data.settings['view options']) {
416 + utils.shallowCopyFromList(opts, data.settings['view options'], _OPTS_EXPRESS);
417 + }
418 + if (data.settings.views) {
419 + opts.views = data.settings.views;
420 + }
421 + }
422 + // Express 3 and lower
423 + else {
424 + utils.shallowCopyFromList(opts, data, _OPTS_EXPRESS);
425 + }
426 + }
427 + else {
428 + // Use shallowCopy so we don't pollute passed in opts obj with new vals
429 + utils.shallowCopy(opts, arguments[2]);
430 + }
431 +
432 + opts.filename = filename;
433 + }
434 + else {
435 + data = {};
436 + }
437 +
438 + return tryHandleCache(opts, data, cb);
439 +};
440 +
441 +/**
442 + * Clear intermediate JavaScript cache. Calls {@link Cache#reset}.
443 + * @public
444 + */
445 +
446 +exports.clearCache = function () {
447 + exports.cache.reset();
448 +};
449 +
450 +function Template(text, opts) {
451 + opts = opts || {};
452 + var options = {};
453 + this.templateText = text;
454 + this.mode = null;
455 + this.truncate = false;
456 + this.currentLine = 1;
457 + this.source = '';
458 + this.dependencies = [];
459 + options.client = opts.client || false;
460 + options.escapeFunction = opts.escape || utils.escapeXML;
461 + options.compileDebug = opts.compileDebug !== false;
462 + options.debug = !!opts.debug;
463 + options.filename = opts.filename;
464 + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER;
465 + options.strict = opts.strict || false;
466 + options.context = opts.context;
467 + options.cache = opts.cache || false;
468 + options.rmWhitespace = opts.rmWhitespace;
469 + options.root = opts.root;
470 + options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME;
471 + options.views = opts.views;
472 +
473 + if (options.strict) {
474 + options._with = false;
475 + }
476 + else {
477 + options._with = typeof opts._with != 'undefined' ? opts._with : true;
478 + }
479 +
480 + this.opts = options;
481 +
482 + this.regex = this.createRegex();
483 +}
484 +
485 +Template.modes = {
486 + EVAL: 'eval',
487 + ESCAPED: 'escaped',
488 + RAW: 'raw',
489 + COMMENT: 'comment',
490 + LITERAL: 'literal'
491 +};
492 +
493 +Template.prototype = {
494 + createRegex: function () {
495 + var str = _REGEX_STRING;
496 + var delim = utils.escapeRegExpChars(this.opts.delimiter);
497 + str = str.replace(/%/g, delim);
498 + return new RegExp(str);
499 + },
500 +
501 + compile: function () {
502 + var src;
503 + var fn;
504 + var opts = this.opts;
505 + var prepended = '';
506 + var appended = '';
507 + var escapeFn = opts.escapeFunction;
508 +
509 + if (!this.source) {
510 + this.generateSource();
511 + prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n';
512 + if (opts._with !== false) {
513 + prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
514 + appended += ' }' + '\n';
515 + }
516 + appended += ' return __output.join("");' + '\n';
517 + this.source = prepended + this.source + appended;
518 + }
519 +
520 + if (opts.compileDebug) {
521 + src = 'var __line = 1' + '\n'
522 + + ' , __lines = ' + JSON.stringify(this.templateText) + '\n'
523 + + ' , __filename = ' + (opts.filename ?
524 + JSON.stringify(opts.filename) : 'undefined') + ';' + '\n'
525 + + 'try {' + '\n'
526 + + this.source
527 + + '} catch (e) {' + '\n'
528 + + ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n'
529 + + '}' + '\n';
530 + }
531 + else {
532 + src = this.source;
533 + }
534 +
535 + if (opts.client) {
536 + src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src;
537 + if (opts.compileDebug) {
538 + src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src;
539 + }
540 + }
541 +
542 + if (opts.strict) {
543 + src = '"use strict";\n' + src;
544 + }
545 + if (opts.debug) {
546 + console.log(src);
547 + }
548 +
549 + try {
550 + fn = new Function(opts.localsName + ', escapeFn, include, rethrow', src);
551 + }
552 + catch(e) {
553 + // istanbul ignore else
554 + if (e instanceof SyntaxError) {
555 + if (opts.filename) {
556 + e.message += ' in ' + opts.filename;
557 + }
558 + e.message += ' while compiling ejs\n\n';
559 + e.message += 'If the above error is not helpful, you may want to try EJS-Lint:\n';
560 + e.message += 'https://github.com/RyanZim/EJS-Lint';
561 + }
562 + throw e;
563 + }
564 +
565 + if (opts.client) {
566 + fn.dependencies = this.dependencies;
567 + return fn;
568 + }
569 +
570 + // Return a callable function which will execute the function
571 + // created by the source-code, with the passed data as locals
572 + // Adds a local `include` function which allows full recursive include
573 + var returnedFn = function (data) {
574 + var include = function (path, includeData) {
575 + var d = utils.shallowCopy({}, data);
576 + if (includeData) {
577 + d = utils.shallowCopy(d, includeData);
578 + }
579 + return includeFile(path, opts)(d);
580 + };
581 + return fn.apply(opts.context, [data || {}, escapeFn, include, rethrow]);
582 + };
583 + returnedFn.dependencies = this.dependencies;
584 + return returnedFn;
585 + },
586 +
587 + generateSource: function () {
588 + var opts = this.opts;
589 +
590 + if (opts.rmWhitespace) {
591 + // Have to use two separate replace here as `^` and `$` operators don't
592 + // work well with `\r`.
593 + this.templateText =
594 + this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, '');
595 + }
596 +
597 + // Slurp spaces and tabs before <%_ and after _%>
598 + this.templateText =
599 + this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>');
600 +
601 + var self = this;
602 + var matches = this.parseTemplateText();
603 + var d = this.opts.delimiter;
604 +
605 + if (matches && matches.length) {
606 + matches.forEach(function (line, index) {
607 + var opening;
608 + var closing;
609 + var include;
610 + var includeOpts;
611 + var includeObj;
612 + var includeSrc;
613 + // If this is an opening tag, check for closing tags
614 + // FIXME: May end up with some false positives here
615 + // Better to store modes as k/v with '<' + delimiter as key
616 + // Then this can simply check against the map
617 + if ( line.indexOf('<' + d) === 0 // If it is a tag
618 + && line.indexOf('<' + d + d) !== 0) { // and is not escaped
619 + closing = matches[index + 2];
620 + if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) {
621 + throw new Error('Could not find matching close tag for "' + line + '".');
622 + }
623 + }
624 + // HACK: backward-compat `include` preprocessor directives
625 + if ((include = line.match(/^\s*include\s+(\S+)/))) {
626 + opening = matches[index - 1];
627 + // Must be in EVAL or RAW mode
628 + if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) {
629 + includeOpts = utils.shallowCopy({}, self.opts);
630 + includeObj = includeSource(include[1], includeOpts);
631 + if (self.opts.compileDebug) {
632 + includeSrc =
633 + ' ; (function(){' + '\n'
634 + + ' var __line = 1' + '\n'
635 + + ' , __lines = ' + JSON.stringify(includeObj.template) + '\n'
636 + + ' , __filename = ' + JSON.stringify(includeObj.filename) + ';' + '\n'
637 + + ' try {' + '\n'
638 + + includeObj.source
639 + + ' } catch (e) {' + '\n'
640 + + ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n'
641 + + ' }' + '\n'
642 + + ' ; }).call(this)' + '\n';
643 + }else{
644 + includeSrc = ' ; (function(){' + '\n' + includeObj.source +
645 + ' ; }).call(this)' + '\n';
646 + }
647 + self.source += includeSrc;
648 + self.dependencies.push(exports.resolveInclude(include[1],
649 + includeOpts.filename));
650 + return;
651 + }
652 + }
653 + self.scanLine(line);
654 + });
655 + }
656 +
657 + },
658 +
659 + parseTemplateText: function () {
660 + var str = this.templateText;
661 + var pat = this.regex;
662 + var result = pat.exec(str);
663 + var arr = [];
664 + var firstPos;
665 +
666 + while (result) {
667 + firstPos = result.index;
668 +
669 + if (firstPos !== 0) {
670 + arr.push(str.substring(0, firstPos));
671 + str = str.slice(firstPos);
672 + }
673 +
674 + arr.push(result[0]);
675 + str = str.slice(result[0].length);
676 + result = pat.exec(str);
677 + }
678 +
679 + if (str) {
680 + arr.push(str);
681 + }
682 +
683 + return arr;
684 + },
685 +
686 + _addOutput: function (line) {
687 + if (this.truncate) {
688 + // Only replace single leading linebreak in the line after
689 + // -%> tag -- this is the single, trailing linebreak
690 + // after the tag that the truncation mode replaces
691 + // Handle Win / Unix / old Mac linebreaks -- do the \r\n
692 + // combo first in the regex-or
693 + line = line.replace(/^(?:\r\n|\r|\n)/, '');
694 + this.truncate = false;
695 + }
696 + else if (this.opts.rmWhitespace) {
697 + // rmWhitespace has already removed trailing spaces, just need
698 + // to remove linebreaks
699 + line = line.replace(/^\n/, '');
700 + }
701 + if (!line) {
702 + return line;
703 + }
704 +
705 + // Preserve literal slashes
706 + line = line.replace(/\\/g, '\\\\');
707 +
708 + // Convert linebreaks
709 + line = line.replace(/\n/g, '\\n');
710 + line = line.replace(/\r/g, '\\r');
711 +
712 + // Escape double-quotes
713 + // - this will be the delimiter during execution
714 + line = line.replace(/"/g, '\\"');
715 + this.source += ' ; __append("' + line + '")' + '\n';
716 + },
717 +
718 + scanLine: function (line) {
719 + var self = this;
720 + var d = this.opts.delimiter;
721 + var newLineCount = 0;
722 +
723 + newLineCount = (line.split('\n').length - 1);
724 +
725 + switch (line) {
726 + case '<' + d:
727 + case '<' + d + '_':
728 + this.mode = Template.modes.EVAL;
729 + break;
730 + case '<' + d + '=':
731 + this.mode = Template.modes.ESCAPED;
732 + break;
733 + case '<' + d + '-':
734 + this.mode = Template.modes.RAW;
735 + break;
736 + case '<' + d + '#':
737 + this.mode = Template.modes.COMMENT;
738 + break;
739 + case '<' + d + d:
740 + this.mode = Template.modes.LITERAL;
741 + this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n';
742 + break;
743 + case d + d + '>':
744 + this.mode = Template.modes.LITERAL;
745 + this.source += ' ; __append("' + line.replace(d + d + '>', d + '>') + '")' + '\n';
746 + break;
747 + case d + '>':
748 + case '-' + d + '>':
749 + case '_' + d + '>':
750 + if (this.mode == Template.modes.LITERAL) {
751 + this._addOutput(line);
752 + }
753 +
754 + this.mode = null;
755 + this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0;
756 + break;
757 + default:
758 + // In script mode, depends on type of tag
759 + if (this.mode) {
760 + // If '//' is found without a line break, add a line break.
761 + switch (this.mode) {
762 + case Template.modes.EVAL:
763 + case Template.modes.ESCAPED:
764 + case Template.modes.RAW:
765 + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) {
766 + line += '\n';
767 + }
768 + }
769 + switch (this.mode) {
770 + // Just executing code
771 + case Template.modes.EVAL:
772 + this.source += ' ; ' + line + '\n';
773 + break;
774 + // Exec, esc, and output
775 + case Template.modes.ESCAPED:
776 + this.source += ' ; __append(escapeFn(' + stripSemi(line) + '))' + '\n';
777 + break;
778 + // Exec and output
779 + case Template.modes.RAW:
780 + this.source += ' ; __append(' + stripSemi(line) + ')' + '\n';
781 + break;
782 + case Template.modes.COMMENT:
783 + // Do nothing
784 + break;
785 + // Literal <%% mode, append as raw output
786 + case Template.modes.LITERAL:
787 + this._addOutput(line);
788 + break;
789 + }
790 + }
791 + // In string mode, just add the output
792 + else {
793 + this._addOutput(line);
794 + }
795 + }
796 +
797 + if (self.opts.compileDebug && newLineCount) {
798 + this.currentLine += newLineCount;
799 + this.source += ' ; __line = ' + this.currentLine + '\n';
800 + }
801 + }
802 +};
803 +
804 +/**
805 + * Escape characters reserved in XML.
806 + *
807 + * This is simply an export of {@link module:utils.escapeXML}.
808 + *
809 + * If `markup` is `undefined` or `null`, the empty string is returned.
810 + *
811 + * @param {String} markup Input string
812 + * @return {String} Escaped string
813 + * @public
814 + * @func
815 + * */
816 +exports.escapeXML = utils.escapeXML;
817 +
818 +/**
819 + * Express.js support.
820 + *
821 + * This is an alias for {@link module:ejs.renderFile}, in order to support
822 + * Express.js out-of-the-box.
823 + *
824 + * @func
825 + */
826 +
827 +exports.__express = exports.renderFile;
828 +
829 +// Add require support
830 +/* istanbul ignore else */
831 +if (require.extensions) {
832 + require.extensions['.ejs'] = function (module, flnm) {
833 + var filename = flnm || /* istanbul ignore next */ module.filename;
834 + var options = {
835 + filename: filename,
836 + client: true
837 + };
838 + var template = fileLoader(filename).toString();
839 + var fn = exports.compile(template, options);
840 + module._compile('module.exports = ' + fn.toString() + ';', filename);
841 + };
842 +}
843 +
844 +/**
845 + * Version of EJS.
846 + *
847 + * @readonly
848 + * @type {String}
849 + * @public
850 + */
851 +
852 +exports.VERSION = _VERSION_STRING;
853 +
854 +/**
855 + * Name for detection of EJS.
856 + *
857 + * @readonly
858 + * @type {String}
859 + * @public
860 + */
861 +
862 +exports.name = _NAME;
863 +
864 +/* istanbul ignore if */
865 +if (typeof window != 'undefined') {
866 + window.ejs = exports;
867 +}
868 +
869 +},{"../package.json":6,"./utils":2,"fs":3,"path":4}],2:[function(require,module,exports){
870 +/*
871 + * EJS Embedded JavaScript templates
872 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
873 + *
874 + * Licensed under the Apache License, Version 2.0 (the "License");
875 + * you may not use this file except in compliance with the License.
876 + * You may obtain a copy of the License at
877 + *
878 + * http://www.apache.org/licenses/LICENSE-2.0
879 + *
880 + * Unless required by applicable law or agreed to in writing, software
881 + * distributed under the License is distributed on an "AS IS" BASIS,
882 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
883 + * See the License for the specific language governing permissions and
884 + * limitations under the License.
885 + *
886 +*/
887 +
888 +/**
889 + * Private utility functions
890 + * @module utils
891 + * @private
892 + */
893 +
894 +'use strict';
895 +
896 +var regExpChars = /[|\\{}()[\]^$+*?.]/g;
897 +
898 +/**
899 + * Escape characters reserved in regular expressions.
900 + *
901 + * If `string` is `undefined` or `null`, the empty string is returned.
902 + *
903 + * @param {String} string Input string
904 + * @return {String} Escaped string
905 + * @static
906 + * @private
907 + */
908 +exports.escapeRegExpChars = function (string) {
909 + // istanbul ignore if
910 + if (!string) {
911 + return '';
912 + }
913 + return String(string).replace(regExpChars, '\\$&');
914 +};
915 +
916 +var _ENCODE_HTML_RULES = {
917 + '&': '&amp;',
918 + '<': '&lt;',
919 + '>': '&gt;',
920 + '"': '&#34;',
921 + "'": '&#39;'
922 +};
923 +var _MATCH_HTML = /[&<>\'"]/g;
924 +
925 +function encode_char(c) {
926 + return _ENCODE_HTML_RULES[c] || c;
927 +}
928 +
929 +/**
930 + * Stringified version of constants used by {@link module:utils.escapeXML}.
931 + *
932 + * It is used in the process of generating {@link ClientFunction}s.
933 + *
934 + * @readonly
935 + * @type {String}
936 + */
937 +
938 +var escapeFuncStr =
939 + 'var _ENCODE_HTML_RULES = {\n'
940 ++ ' "&": "&amp;"\n'
941 ++ ' , "<": "&lt;"\n'
942 ++ ' , ">": "&gt;"\n'
943 ++ ' , \'"\': "&#34;"\n'
944 ++ ' , "\'": "&#39;"\n'
945 ++ ' }\n'
946 ++ ' , _MATCH_HTML = /[&<>\'"]/g;\n'
947 ++ 'function encode_char(c) {\n'
948 ++ ' return _ENCODE_HTML_RULES[c] || c;\n'
949 ++ '};\n';
950 +
951 +/**
952 + * Escape characters reserved in XML.
953 + *
954 + * If `markup` is `undefined` or `null`, the empty string is returned.
955 + *
956 + * @implements {EscapeCallback}
957 + * @param {String} markup Input string
958 + * @return {String} Escaped string
959 + * @static
960 + * @private
961 + */
962 +
963 +exports.escapeXML = function (markup) {
964 + return markup == undefined
965 + ? ''
966 + : String(markup)
967 + .replace(_MATCH_HTML, encode_char);
968 +};
969 +exports.escapeXML.toString = function () {
970 + return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr;
971 +};
972 +
973 +/**
974 + * Naive copy of properties from one object to another.
975 + * Does not recurse into non-scalar properties
976 + * Does not check to see if the property has a value before copying
977 + *
978 + * @param {Object} to Destination object
979 + * @param {Object} from Source object
980 + * @return {Object} Destination object
981 + * @static
982 + * @private
983 + */
984 +exports.shallowCopy = function (to, from) {
985 + from = from || {};
986 + for (var p in from) {
987 + to[p] = from[p];
988 + }
989 + return to;
990 +};
991 +
992 +/**
993 + * Naive copy of a list of key names, from one object to another.
994 + * Only copies property if it is actually defined
995 + * Does not recurse into non-scalar properties
996 + *
997 + * @param {Object} to Destination object
998 + * @param {Object} from Source object
999 + * @param {Array} list List of properties to copy
1000 + * @return {Object} Destination object
1001 + * @static
1002 + * @private
1003 + */
1004 +exports.shallowCopyFromList = function (to, from, list) {
1005 + for (var i = 0; i < list.length; i++) {
1006 + var p = list[i];
1007 + if (typeof from[p] != 'undefined') {
1008 + to[p] = from[p];
1009 + }
1010 + }
1011 + return to;
1012 +};
1013 +
1014 +/**
1015 + * Simple in-process cache implementation. Does not implement limits of any
1016 + * sort.
1017 + *
1018 + * @implements Cache
1019 + * @static
1020 + * @private
1021 + */
1022 +exports.cache = {
1023 + _data: {},
1024 + set: function (key, val) {
1025 + this._data[key] = val;
1026 + },
1027 + get: function (key) {
1028 + return this._data[key];
1029 + },
1030 + reset: function () {
1031 + this._data = {};
1032 + }
1033 +};
1034 +
1035 +},{}],3:[function(require,module,exports){
1036 +
1037 +},{}],4:[function(require,module,exports){
1038 +(function (process){
1039 +// Copyright Joyent, Inc. and other Node contributors.
1040 +//
1041 +// Permission is hereby granted, free of charge, to any person obtaining a
1042 +// copy of this software and associated documentation files (the
1043 +// "Software"), to deal in the Software without restriction, including
1044 +// without limitation the rights to use, copy, modify, merge, publish,
1045 +// distribute, sublicense, and/or sell copies of the Software, and to permit
1046 +// persons to whom the Software is furnished to do so, subject to the
1047 +// following conditions:
1048 +//
1049 +// The above copyright notice and this permission notice shall be included
1050 +// in all copies or substantial portions of the Software.
1051 +//
1052 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1053 +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1054 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
1055 +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
1056 +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1057 +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1058 +// USE OR OTHER DEALINGS IN THE SOFTWARE.
1059 +
1060 +// resolves . and .. elements in a path array with directory names there
1061 +// must be no slashes, empty elements, or device names (c:\) in the array
1062 +// (so also no leading and trailing slashes - it does not distinguish
1063 +// relative and absolute paths)
1064 +function normalizeArray(parts, allowAboveRoot) {
1065 + // if the path tries to go above the root, `up` ends up > 0
1066 + var up = 0;
1067 + for (var i = parts.length - 1; i >= 0; i--) {
1068 + var last = parts[i];
1069 + if (last === '.') {
1070 + parts.splice(i, 1);
1071 + } else if (last === '..') {
1072 + parts.splice(i, 1);
1073 + up++;
1074 + } else if (up) {
1075 + parts.splice(i, 1);
1076 + up--;
1077 + }
1078 + }
1079 +
1080 + // if the path is allowed to go above the root, restore leading ..s
1081 + if (allowAboveRoot) {
1082 + for (; up--; up) {
1083 + parts.unshift('..');
1084 + }
1085 + }
1086 +
1087 + return parts;
1088 +}
1089 +
1090 +// Split a filename into [root, dir, basename, ext], unix version
1091 +// 'root' is just a slash, or nothing.
1092 +var splitPathRe =
1093 + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
1094 +var splitPath = function(filename) {
1095 + return splitPathRe.exec(filename).slice(1);
1096 +};
1097 +
1098 +// path.resolve([from ...], to)
1099 +// posix version
1100 +exports.resolve = function() {
1101 + var resolvedPath = '',
1102 + resolvedAbsolute = false;
1103 +
1104 + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
1105 + var path = (i >= 0) ? arguments[i] : process.cwd();
1106 +
1107 + // Skip empty and invalid entries
1108 + if (typeof path !== 'string') {
1109 + throw new TypeError('Arguments to path.resolve must be strings');
1110 + } else if (!path) {
1111 + continue;
1112 + }
1113 +
1114 + resolvedPath = path + '/' + resolvedPath;
1115 + resolvedAbsolute = path.charAt(0) === '/';
1116 + }
1117 +
1118 + // At this point the path should be resolved to a full absolute path, but
1119 + // handle relative paths to be safe (might happen when process.cwd() fails)
1120 +
1121 + // Normalize the path
1122 + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
1123 + return !!p;
1124 + }), !resolvedAbsolute).join('/');
1125 +
1126 + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
1127 +};
1128 +
1129 +// path.normalize(path)
1130 +// posix version
1131 +exports.normalize = function(path) {
1132 + var isAbsolute = exports.isAbsolute(path),
1133 + trailingSlash = substr(path, -1) === '/';
1134 +
1135 + // Normalize the path
1136 + path = normalizeArray(filter(path.split('/'), function(p) {
1137 + return !!p;
1138 + }), !isAbsolute).join('/');
1139 +
1140 + if (!path && !isAbsolute) {
1141 + path = '.';
1142 + }
1143 + if (path && trailingSlash) {
1144 + path += '/';
1145 + }
1146 +
1147 + return (isAbsolute ? '/' : '') + path;
1148 +};
1149 +
1150 +// posix version
1151 +exports.isAbsolute = function(path) {
1152 + return path.charAt(0) === '/';
1153 +};
1154 +
1155 +// posix version
1156 +exports.join = function() {
1157 + var paths = Array.prototype.slice.call(arguments, 0);
1158 + return exports.normalize(filter(paths, function(p, index) {
1159 + if (typeof p !== 'string') {
1160 + throw new TypeError('Arguments to path.join must be strings');
1161 + }
1162 + return p;
1163 + }).join('/'));
1164 +};
1165 +
1166 +
1167 +// path.relative(from, to)
1168 +// posix version
1169 +exports.relative = function(from, to) {
1170 + from = exports.resolve(from).substr(1);
1171 + to = exports.resolve(to).substr(1);
1172 +
1173 + function trim(arr) {
1174 + var start = 0;
1175 + for (; start < arr.length; start++) {
1176 + if (arr[start] !== '') break;
1177 + }
1178 +
1179 + var end = arr.length - 1;
1180 + for (; end >= 0; end--) {
1181 + if (arr[end] !== '') break;
1182 + }
1183 +
1184 + if (start > end) return [];
1185 + return arr.slice(start, end - start + 1);
1186 + }
1187 +
1188 + var fromParts = trim(from.split('/'));
1189 + var toParts = trim(to.split('/'));
1190 +
1191 + var length = Math.min(fromParts.length, toParts.length);
1192 + var samePartsLength = length;
1193 + for (var i = 0; i < length; i++) {
1194 + if (fromParts[i] !== toParts[i]) {
1195 + samePartsLength = i;
1196 + break;
1197 + }
1198 + }
1199 +
1200 + var outputParts = [];
1201 + for (var i = samePartsLength; i < fromParts.length; i++) {
1202 + outputParts.push('..');
1203 + }
1204 +
1205 + outputParts = outputParts.concat(toParts.slice(samePartsLength));
1206 +
1207 + return outputParts.join('/');
1208 +};
1209 +
1210 +exports.sep = '/';
1211 +exports.delimiter = ':';
1212 +
1213 +exports.dirname = function(path) {
1214 + var result = splitPath(path),
1215 + root = result[0],
1216 + dir = result[1];
1217 +
1218 + if (!root && !dir) {
1219 + // No dirname whatsoever
1220 + return '.';
1221 + }
1222 +
1223 + if (dir) {
1224 + // It has a dirname, strip trailing slash
1225 + dir = dir.substr(0, dir.length - 1);
1226 + }
1227 +
1228 + return root + dir;
1229 +};
1230 +
1231 +
1232 +exports.basename = function(path, ext) {
1233 + var f = splitPath(path)[2];
1234 + // TODO: make this comparison case-insensitive on windows?
1235 + if (ext && f.substr(-1 * ext.length) === ext) {
1236 + f = f.substr(0, f.length - ext.length);
1237 + }
1238 + return f;
1239 +};
1240 +
1241 +
1242 +exports.extname = function(path) {
1243 + return splitPath(path)[3];
1244 +};
1245 +
1246 +function filter (xs, f) {
1247 + if (xs.filter) return xs.filter(f);
1248 + var res = [];
1249 + for (var i = 0; i < xs.length; i++) {
1250 + if (f(xs[i], i, xs)) res.push(xs[i]);
1251 + }
1252 + return res;
1253 +}
1254 +
1255 +// String.prototype.substr - negative index don't work in IE8
1256 +var substr = 'ab'.substr(-1) === 'b'
1257 + ? function (str, start, len) { return str.substr(start, len) }
1258 + : function (str, start, len) {
1259 + if (start < 0) start = str.length + start;
1260 + return str.substr(start, len);
1261 + }
1262 +;
1263 +
1264 +}).call(this,require('_process'))
1265 +},{"_process":5}],5:[function(require,module,exports){
1266 +// shim for using process in browser
1267 +var process = module.exports = {};
1268 +
1269 +// cached from whatever global is present so that test runners that stub it
1270 +// don't break things. But we need to wrap it in a try catch in case it is
1271 +// wrapped in strict mode code which doesn't define any globals. It's inside a
1272 +// function because try/catches deoptimize in certain engines.
1273 +
1274 +var cachedSetTimeout;
1275 +var cachedClearTimeout;
1276 +
1277 +function defaultSetTimout() {
1278 + throw new Error('setTimeout has not been defined');
1279 +}
1280 +function defaultClearTimeout () {
1281 + throw new Error('clearTimeout has not been defined');
1282 +}
1283 +(function () {
1284 + try {
1285 + if (typeof setTimeout === 'function') {
1286 + cachedSetTimeout = setTimeout;
1287 + } else {
1288 + cachedSetTimeout = defaultSetTimout;
1289 + }
1290 + } catch (e) {
1291 + cachedSetTimeout = defaultSetTimout;
1292 + }
1293 + try {
1294 + if (typeof clearTimeout === 'function') {
1295 + cachedClearTimeout = clearTimeout;
1296 + } else {
1297 + cachedClearTimeout = defaultClearTimeout;
1298 + }
1299 + } catch (e) {
1300 + cachedClearTimeout = defaultClearTimeout;
1301 + }
1302 +} ())
1303 +function runTimeout(fun) {
1304 + if (cachedSetTimeout === setTimeout) {
1305 + //normal enviroments in sane situations
1306 + return setTimeout(fun, 0);
1307 + }
1308 + // if setTimeout wasn't available but was latter defined
1309 + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
1310 + cachedSetTimeout = setTimeout;
1311 + return setTimeout(fun, 0);
1312 + }
1313 + try {
1314 + // when when somebody has screwed with setTimeout but no I.E. maddness
1315 + return cachedSetTimeout(fun, 0);
1316 + } catch(e){
1317 + try {
1318 + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
1319 + return cachedSetTimeout.call(null, fun, 0);
1320 + } catch(e){
1321 + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
1322 + return cachedSetTimeout.call(this, fun, 0);
1323 + }
1324 + }
1325 +
1326 +
1327 +}
1328 +function runClearTimeout(marker) {
1329 + if (cachedClearTimeout === clearTimeout) {
1330 + //normal enviroments in sane situations
1331 + return clearTimeout(marker);
1332 + }
1333 + // if clearTimeout wasn't available but was latter defined
1334 + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
1335 + cachedClearTimeout = clearTimeout;
1336 + return clearTimeout(marker);
1337 + }
1338 + try {
1339 + // when when somebody has screwed with setTimeout but no I.E. maddness
1340 + return cachedClearTimeout(marker);
1341 + } catch (e){
1342 + try {
1343 + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
1344 + return cachedClearTimeout.call(null, marker);
1345 + } catch (e){
1346 + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
1347 + // Some versions of I.E. have different rules for clearTimeout vs setTimeout
1348 + return cachedClearTimeout.call(this, marker);
1349 + }
1350 + }
1351 +
1352 +
1353 +
1354 +}
1355 +var queue = [];
1356 +var draining = false;
1357 +var currentQueue;
1358 +var queueIndex = -1;
1359 +
1360 +function cleanUpNextTick() {
1361 + if (!draining || !currentQueue) {
1362 + return;
1363 + }
1364 + draining = false;
1365 + if (currentQueue.length) {
1366 + queue = currentQueue.concat(queue);
1367 + } else {
1368 + queueIndex = -1;
1369 + }
1370 + if (queue.length) {
1371 + drainQueue();
1372 + }
1373 +}
1374 +
1375 +function drainQueue() {
1376 + if (draining) {
1377 + return;
1378 + }
1379 + var timeout = runTimeout(cleanUpNextTick);
1380 + draining = true;
1381 +
1382 + var len = queue.length;
1383 + while(len) {
1384 + currentQueue = queue;
1385 + queue = [];
1386 + while (++queueIndex < len) {
1387 + if (currentQueue) {
1388 + currentQueue[queueIndex].run();
1389 + }
1390 + }
1391 + queueIndex = -1;
1392 + len = queue.length;
1393 + }
1394 + currentQueue = null;
1395 + draining = false;
1396 + runClearTimeout(timeout);
1397 +}
1398 +
1399 +process.nextTick = function (fun) {
1400 + var args = new Array(arguments.length - 1);
1401 + if (arguments.length > 1) {
1402 + for (var i = 1; i < arguments.length; i++) {
1403 + args[i - 1] = arguments[i];
1404 + }
1405 + }
1406 + queue.push(new Item(fun, args));
1407 + if (queue.length === 1 && !draining) {
1408 + runTimeout(drainQueue);
1409 + }
1410 +};
1411 +
1412 +// v8 likes predictible objects
1413 +function Item(fun, array) {
1414 + this.fun = fun;
1415 + this.array = array;
1416 +}
1417 +Item.prototype.run = function () {
1418 + this.fun.apply(null, this.array);
1419 +};
1420 +process.title = 'browser';
1421 +process.browser = true;
1422 +process.env = {};
1423 +process.argv = [];
1424 +process.version = ''; // empty string to avoid regexp issues
1425 +process.versions = {};
1426 +
1427 +function noop() {}
1428 +
1429 +process.on = noop;
1430 +process.addListener = noop;
1431 +process.once = noop;
1432 +process.off = noop;
1433 +process.removeListener = noop;
1434 +process.removeAllListeners = noop;
1435 +process.emit = noop;
1436 +
1437 +process.binding = function (name) {
1438 + throw new Error('process.binding is not supported');
1439 +};
1440 +
1441 +process.cwd = function () { return '/' };
1442 +process.chdir = function (dir) {
1443 + throw new Error('process.chdir is not supported');
1444 +};
1445 +process.umask = function() { return 0; };
1446 +
1447 +},{}],6:[function(require,module,exports){
1448 +module.exports={
1449 + "name": "ejs",
1450 + "description": "Embedded JavaScript templates",
1451 + "keywords": [
1452 + "template",
1453 + "engine",
1454 + "ejs"
1455 + ],
1456 + "version": "2.5.6",
1457 + "author": "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",
1458 + "contributors": [
1459 + "Timothy Gu <timothygu99@gmail.com> (https://timothygu.github.io)"
1460 + ],
1461 + "license": "Apache-2.0",
1462 + "main": "./lib/ejs.js",
1463 + "repository": {
1464 + "type": "git",
1465 + "url": "git://github.com/mde/ejs.git"
1466 + },
1467 + "bugs": "https://github.com/mde/ejs/issues",
1468 + "homepage": "https://github.com/mde/ejs",
1469 + "dependencies": {},
1470 + "devDependencies": {
1471 + "browserify": "^13.0.1",
1472 + "eslint": "^3.0.0",
1473 + "git-directory-deploy": "^1.5.1",
1474 + "istanbul": "~0.4.3",
1475 + "jake": "^8.0.0",
1476 + "jsdoc": "^3.4.0",
1477 + "lru-cache": "^4.0.1",
1478 + "mocha": "^3.0.2",
1479 + "uglify-js": "^2.6.2"
1480 + },
1481 + "engines": {
1482 + "node": ">=0.10.0"
1483 + },
1484 + "scripts": {
1485 + "test": "jake test",
1486 + "lint": "eslint \"**/*.js\" Jakefile",
1487 + "coverage": "istanbul cover node_modules/mocha/bin/_mocha",
1488 + "doc": "jake doc",
1489 + "devdoc": "jake doc[dev]"
1490 + }
1491 +}
1492 +
1493 +},{}]},{},[1])(1)
1494 +});
...\ No newline at end of file ...\ No newline at end of file
1 +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ejs=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){"use strict";var fs=require("fs");var path=require("path");var utils=require("./utils");var scopeOptionWarned=false;var _VERSION_STRING=require("../package.json").version;var _DEFAULT_DELIMITER="%";var _DEFAULT_LOCALS_NAME="locals";var _NAME="ejs";var _REGEX_STRING="(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)";var _OPTS=["delimiter","scope","context","debug","compileDebug","client","_with","rmWhitespace","strict","filename"];var _OPTS_EXPRESS=_OPTS.concat("cache");var _BOM=/^\uFEFF/;exports.cache=utils.cache;exports.fileLoader=fs.readFileSync;exports.localsName=_DEFAULT_LOCALS_NAME;exports.resolveInclude=function(name,filename,isDir){var dirname=path.dirname;var extname=path.extname;var resolve=path.resolve;var includePath=resolve(isDir?filename:dirname(filename),name);var ext=extname(name);if(!ext){includePath+=".ejs"}return includePath};function getIncludePath(path,options){var includePath;var filePath;var views=options.views;if(path.charAt(0)=="/"){includePath=exports.resolveInclude(path.replace(/^\/*/,""),options.root||"/",true)}else{if(options.filename){filePath=exports.resolveInclude(path,options.filename);if(fs.existsSync(filePath)){includePath=filePath}}if(!includePath){if(Array.isArray(views)&&views.some(function(v){filePath=exports.resolveInclude(path,v,true);return fs.existsSync(filePath)})){includePath=filePath}}if(!includePath){throw new Error("Could not find include include file.")}}return includePath}function handleCache(options,template){var func;var filename=options.filename;var hasTemplate=arguments.length>1;if(options.cache){if(!filename){throw new Error("cache option requires a filename")}func=exports.cache.get(filename);if(func){return func}if(!hasTemplate){template=fileLoader(filename).toString().replace(_BOM,"")}}else if(!hasTemplate){if(!filename){throw new Error("Internal EJS error: no file name or template "+"provided")}template=fileLoader(filename).toString().replace(_BOM,"")}func=exports.compile(template,options);if(options.cache){exports.cache.set(filename,func)}return func}function tryHandleCache(options,data,cb){var result;try{result=handleCache(options)(data)}catch(err){return cb(err)}return cb(null,result)}function fileLoader(filePath){return exports.fileLoader(filePath)}function includeFile(path,options){var opts=utils.shallowCopy({},options);opts.filename=getIncludePath(path,opts);return handleCache(opts)}function includeSource(path,options){var opts=utils.shallowCopy({},options);var includePath;var template;includePath=getIncludePath(path,opts);template=fileLoader(includePath).toString().replace(_BOM,"");opts.filename=includePath;var templ=new Template(template,opts);templ.generateSource();return{source:templ.source,filename:includePath,template:template}}function rethrow(err,str,flnm,lineno,esc){var lines=str.split("\n");var start=Math.max(lineno-3,0);var end=Math.min(lines.length,lineno+3);var filename=esc(flnm);var context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?" >> ":" ")+curr+"| "+line}).join("\n");err.path=filename;err.message=(filename||"ejs")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err}function stripSemi(str){return str.replace(/;(\s*$)/,"$1")}exports.compile=function compile(template,opts){var templ;if(opts&&opts.scope){if(!scopeOptionWarned){console.warn("`scope` option is deprecated and will be removed in EJS 3");scopeOptionWarned=true}if(!opts.context){opts.context=opts.scope}delete opts.scope}templ=new Template(template,opts);return templ.compile()};exports.render=function(template,d,o){var data=d||{};var opts=o||{};if(arguments.length==2){utils.shallowCopyFromList(opts,data,_OPTS)}return handleCache(opts,template)(data)};exports.renderFile=function(){var filename=arguments[0];var cb=arguments[arguments.length-1];var opts={filename:filename};var data;if(arguments.length>2){data=arguments[1];if(arguments.length===3){if(data.settings){if(data.settings["view options"]){utils.shallowCopyFromList(opts,data.settings["view options"],_OPTS_EXPRESS)}if(data.settings.views){opts.views=data.settings.views}}else{utils.shallowCopyFromList(opts,data,_OPTS_EXPRESS)}}else{utils.shallowCopy(opts,arguments[2])}opts.filename=filename}else{data={}}return tryHandleCache(opts,data,cb)};exports.clearCache=function(){exports.cache.reset()};function Template(text,opts){opts=opts||{};var options={};this.templateText=text;this.mode=null;this.truncate=false;this.currentLine=1;this.source="";this.dependencies=[];options.client=opts.client||false;options.escapeFunction=opts.escape||utils.escapeXML;options.compileDebug=opts.compileDebug!==false;options.debug=!!opts.debug;options.filename=opts.filename;options.delimiter=opts.delimiter||exports.delimiter||_DEFAULT_DELIMITER;options.strict=opts.strict||false;options.context=opts.context;options.cache=opts.cache||false;options.rmWhitespace=opts.rmWhitespace;options.root=opts.root;options.localsName=opts.localsName||exports.localsName||_DEFAULT_LOCALS_NAME;options.views=opts.views;if(options.strict){options._with=false}else{options._with=typeof opts._with!="undefined"?opts._with:true}this.opts=options;this.regex=this.createRegex()}Template.modes={EVAL:"eval",ESCAPED:"escaped",RAW:"raw",COMMENT:"comment",LITERAL:"literal"};Template.prototype={createRegex:function(){var str=_REGEX_STRING;var delim=utils.escapeRegExpChars(this.opts.delimiter);str=str.replace(/%/g,delim);return new RegExp(str)},compile:function(){var src;var fn;var opts=this.opts;var prepended="";var appended="";var escapeFn=opts.escapeFunction;if(!this.source){this.generateSource();prepended+=" var __output = [], __append = __output.push.bind(__output);"+"\n";if(opts._with!==false){prepended+=" with ("+opts.localsName+" || {}) {"+"\n";appended+=" }"+"\n"}appended+=' return __output.join("");'+"\n";this.source=prepended+this.source+appended}if(opts.compileDebug){src="var __line = 1"+"\n"+" , __lines = "+JSON.stringify(this.templateText)+"\n"+" , __filename = "+(opts.filename?JSON.stringify(opts.filename):"undefined")+";"+"\n"+"try {"+"\n"+this.source+"} catch (e) {"+"\n"+" rethrow(e, __lines, __filename, __line, escapeFn);"+"\n"+"}"+"\n"}else{src=this.source}if(opts.client){src="escapeFn = escapeFn || "+escapeFn.toString()+";"+"\n"+src;if(opts.compileDebug){src="rethrow = rethrow || "+rethrow.toString()+";"+"\n"+src}}if(opts.strict){src='"use strict";\n'+src}if(opts.debug){console.log(src)}try{fn=new Function(opts.localsName+", escapeFn, include, rethrow",src)}catch(e){if(e instanceof SyntaxError){if(opts.filename){e.message+=" in "+opts.filename}e.message+=" while compiling ejs\n\n";e.message+="If the above error is not helpful, you may want to try EJS-Lint:\n";e.message+="https://github.com/RyanZim/EJS-Lint"}throw e}if(opts.client){fn.dependencies=this.dependencies;return fn}var returnedFn=function(data){var include=function(path,includeData){var d=utils.shallowCopy({},data);if(includeData){d=utils.shallowCopy(d,includeData)}return includeFile(path,opts)(d)};return fn.apply(opts.context,[data||{},escapeFn,include,rethrow])};returnedFn.dependencies=this.dependencies;return returnedFn},generateSource:function(){var opts=this.opts;if(opts.rmWhitespace){this.templateText=this.templateText.replace(/\r/g,"").replace(/^\s+|\s+$/gm,"")}this.templateText=this.templateText.replace(/[ \t]*<%_/gm,"<%_").replace(/_%>[ \t]*/gm,"_%>");var self=this;var matches=this.parseTemplateText();var d=this.opts.delimiter;if(matches&&matches.length){matches.forEach(function(line,index){var opening;var closing;var include;var includeOpts;var includeObj;var includeSrc;if(line.indexOf("<"+d)===0&&line.indexOf("<"+d+d)!==0){closing=matches[index+2];if(!(closing==d+">"||closing=="-"+d+">"||closing=="_"+d+">")){throw new Error('Could not find matching close tag for "'+line+'".')}}if(include=line.match(/^\s*include\s+(\S+)/)){opening=matches[index-1];if(opening&&(opening=="<"+d||opening=="<"+d+"-"||opening=="<"+d+"_")){includeOpts=utils.shallowCopy({},self.opts);includeObj=includeSource(include[1],includeOpts);if(self.opts.compileDebug){includeSrc=" ; (function(){"+"\n"+" var __line = 1"+"\n"+" , __lines = "+JSON.stringify(includeObj.template)+"\n"+" , __filename = "+JSON.stringify(includeObj.filename)+";"+"\n"+" try {"+"\n"+includeObj.source+" } catch (e) {"+"\n"+" rethrow(e, __lines, __filename, __line, escapeFn);"+"\n"+" }"+"\n"+" ; }).call(this)"+"\n"}else{includeSrc=" ; (function(){"+"\n"+includeObj.source+" ; }).call(this)"+"\n"}self.source+=includeSrc;self.dependencies.push(exports.resolveInclude(include[1],includeOpts.filename));return}}self.scanLine(line)})}},parseTemplateText:function(){var str=this.templateText;var pat=this.regex;var result=pat.exec(str);var arr=[];var firstPos;while(result){firstPos=result.index;if(firstPos!==0){arr.push(str.substring(0,firstPos));str=str.slice(firstPos)}arr.push(result[0]);str=str.slice(result[0].length);result=pat.exec(str)}if(str){arr.push(str)}return arr},_addOutput:function(line){if(this.truncate){line=line.replace(/^(?:\r\n|\r|\n)/,"");this.truncate=false}else if(this.opts.rmWhitespace){line=line.replace(/^\n/,"")}if(!line){return line}line=line.replace(/\\/g,"\\\\");line=line.replace(/\n/g,"\\n");line=line.replace(/\r/g,"\\r");line=line.replace(/"/g,'\\"');this.source+=' ; __append("'+line+'")'+"\n"},scanLine:function(line){var self=this;var d=this.opts.delimiter;var newLineCount=0;newLineCount=line.split("\n").length-1;switch(line){case"<"+d:case"<"+d+"_":this.mode=Template.modes.EVAL;break;case"<"+d+"=":this.mode=Template.modes.ESCAPED;break;case"<"+d+"-":this.mode=Template.modes.RAW;break;case"<"+d+"#":this.mode=Template.modes.COMMENT;break;case"<"+d+d:this.mode=Template.modes.LITERAL;this.source+=' ; __append("'+line.replace("<"+d+d,"<"+d)+'")'+"\n";break;case d+d+">":this.mode=Template.modes.LITERAL;this.source+=' ; __append("'+line.replace(d+d+">",d+">")+'")'+"\n";break;case d+">":case"-"+d+">":case"_"+d+">":if(this.mode==Template.modes.LITERAL){this._addOutput(line)}this.mode=null;this.truncate=line.indexOf("-")===0||line.indexOf("_")===0;break;default:if(this.mode){switch(this.mode){case Template.modes.EVAL:case Template.modes.ESCAPED:case Template.modes.RAW:if(line.lastIndexOf("//")>line.lastIndexOf("\n")){line+="\n"}}switch(this.mode){case Template.modes.EVAL:this.source+=" ; "+line+"\n";break;case Template.modes.ESCAPED:this.source+=" ; __append(escapeFn("+stripSemi(line)+"))"+"\n";break;case Template.modes.RAW:this.source+=" ; __append("+stripSemi(line)+")"+"\n";break;case Template.modes.COMMENT:break;case Template.modes.LITERAL:this._addOutput(line);break}}else{this._addOutput(line)}}if(self.opts.compileDebug&&newLineCount){this.currentLine+=newLineCount;this.source+=" ; __line = "+this.currentLine+"\n"}}};exports.escapeXML=utils.escapeXML;exports.__express=exports.renderFile;if(require.extensions){require.extensions[".ejs"]=function(module,flnm){var filename=flnm||module.filename;var options={filename:filename,client:true};var template=fileLoader(filename).toString();var fn=exports.compile(template,options);module._compile("module.exports = "+fn.toString()+";",filename)}}exports.VERSION=_VERSION_STRING;exports.name=_NAME;if(typeof window!="undefined"){window.ejs=exports}},{"../package.json":6,"./utils":2,fs:3,path:4}],2:[function(require,module,exports){"use strict";var regExpChars=/[|\\{}()[\]^$+*?.]/g;exports.escapeRegExpChars=function(string){if(!string){return""}return String(string).replace(regExpChars,"\\$&")};var _ENCODE_HTML_RULES={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&#34;","'":"&#39;"};var _MATCH_HTML=/[&<>\'"]/g;function encode_char(c){return _ENCODE_HTML_RULES[c]||c}var escapeFuncStr="var _ENCODE_HTML_RULES = {\n"+' "&": "&amp;"\n'+' , "<": "&lt;"\n'+' , ">": "&gt;"\n'+' , \'"\': "&#34;"\n'+' , "\'": "&#39;"\n'+" }\n"+" , _MATCH_HTML = /[&<>'\"]/g;\n"+"function encode_char(c) {\n"+" return _ENCODE_HTML_RULES[c] || c;\n"+"};\n";exports.escapeXML=function(markup){return markup==undefined?"":String(markup).replace(_MATCH_HTML,encode_char)};exports.escapeXML.toString=function(){return Function.prototype.toString.call(this)+";\n"+escapeFuncStr};exports.shallowCopy=function(to,from){from=from||{};for(var p in from){to[p]=from[p]}return to};exports.shallowCopyFromList=function(to,from,list){for(var i=0;i<list.length;i++){var p=list[i];if(typeof from[p]!="undefined"){to[p]=from[p]}}return to};exports.cache={_data:{},set:function(key,val){this._data[key]=val},get:function(key){return this._data[key]},reset:function(){this._data={}}}},{}],3:[function(require,module,exports){},{}],4:[function(require,module,exports){(function(process){function normalizeArray(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up--;up){parts.unshift("..")}}return parts}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;var splitPath=function(filename){return splitPathRe.exec(filename).slice(1)};exports.resolve=function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:process.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){continue}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=normalizeArray(filter(resolvedPath.split("/"),function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."};exports.normalize=function(path){var isAbsolute=exports.isAbsolute(path),trailingSlash=substr(path,-1)==="/";path=normalizeArray(filter(path.split("/"),function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path};exports.isAbsolute=function(path){return path.charAt(0)==="/"};exports.join=function(){var paths=Array.prototype.slice.call(arguments,0);return exports.normalize(filter(paths,function(p,index){if(typeof p!=="string"){throw new TypeError("Arguments to path.join must be strings")}return p}).join("/"))};exports.relative=function(from,to){from=exports.resolve(from).substr(1);to=exports.resolve(to).substr(1);function trim(arr){var start=0;for(;start<arr.length;start++){if(arr[start]!=="")break}var end=arr.length-1;for(;end>=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i<length;i++){if(fromParts[i]!==toParts[i]){samePartsLength=i;break}}var outputParts=[];for(var i=samePartsLength;i<fromParts.length;i++){outputParts.push("..")}outputParts=outputParts.concat(toParts.slice(samePartsLength));return outputParts.join("/")};exports.sep="/";exports.delimiter=":";exports.dirname=function(path){var result=splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir};exports.basename=function(path,ext){var f=splitPath(path)[2];if(ext&&f.substr(-1*ext.length)===ext){f=f.substr(0,f.length-ext.length)}return f};exports.extname=function(path){return splitPath(path)[3]};function filter(xs,f){if(xs.filter)return xs.filter(f);var res=[];for(var i=0;i<xs.length;i++){if(f(xs[i],i,xs))res.push(xs[i])}return res}var substr="ab".substr(-1)==="b"?function(str,start,len){return str.substr(start,len)}:function(str,start,len){if(start<0)start=str.length+start;return str.substr(start,len)}}).call(this,require("_process"))},{_process:5}],5:[function(require,module,exports){var process=module.exports={};var cachedSetTimeout;var cachedClearTimeout;function defaultSetTimout(){throw new Error("setTimeout has not been defined")}function defaultClearTimeout(){throw new Error("clearTimeout has not been defined")}(function(){try{if(typeof setTimeout==="function"){cachedSetTimeout=setTimeout}else{cachedSetTimeout=defaultSetTimout}}catch(e){cachedSetTimeout=defaultSetTimout}try{if(typeof clearTimeout==="function"){cachedClearTimeout=clearTimeout}else{cachedClearTimeout=defaultClearTimeout}}catch(e){cachedClearTimeout=defaultClearTimeout}})();function runTimeout(fun){if(cachedSetTimeout===setTimeout){return setTimeout(fun,0)}if((cachedSetTimeout===defaultSetTimout||!cachedSetTimeout)&&setTimeout){cachedSetTimeout=setTimeout;return setTimeout(fun,0)}try{return cachedSetTimeout(fun,0)}catch(e){try{return cachedSetTimeout.call(null,fun,0)}catch(e){return cachedSetTimeout.call(this,fun,0)}}}function runClearTimeout(marker){if(cachedClearTimeout===clearTimeout){return clearTimeout(marker)}if((cachedClearTimeout===defaultClearTimeout||!cachedClearTimeout)&&clearTimeout){cachedClearTimeout=clearTimeout;return clearTimeout(marker)}try{return cachedClearTimeout(marker)}catch(e){try{return cachedClearTimeout.call(null,marker)}catch(e){return cachedClearTimeout.call(this,marker)}}}var queue=[];var draining=false;var currentQueue;var queueIndex=-1;function cleanUpNextTick(){if(!draining||!currentQueue){return}draining=false;if(currentQueue.length){queue=currentQueue.concat(queue)}else{queueIndex=-1}if(queue.length){drainQueue()}}function drainQueue(){if(draining){return}var timeout=runTimeout(cleanUpNextTick);draining=true;var len=queue.length;while(len){currentQueue=queue;queue=[];while(++queueIndex<len){if(currentQueue){currentQueue[queueIndex].run()}}queueIndex=-1;len=queue.length}currentQueue=null;draining=false;runClearTimeout(timeout)}process.nextTick=function(fun){var args=new Array(arguments.length-1);if(arguments.length>1){for(var i=1;i<arguments.length;i++){args[i-1]=arguments[i]}}queue.push(new Item(fun,args));if(queue.length===1&&!draining){runTimeout(drainQueue)}};function Item(fun,array){this.fun=fun;this.array=array}Item.prototype.run=function(){this.fun.apply(null,this.array)};process.title="browser";process.browser=true;process.env={};process.argv=[];process.version="";process.versions={};function noop(){}process.on=noop;process.addListener=noop;process.once=noop;process.off=noop;process.removeListener=noop;process.removeAllListeners=noop;process.emit=noop;process.binding=function(name){throw new Error("process.binding is not supported")};process.cwd=function(){return"/"};process.chdir=function(dir){throw new Error("process.chdir is not supported")};process.umask=function(){return 0}},{}],6:[function(require,module,exports){module.exports={name:"ejs",description:"Embedded JavaScript templates",keywords:["template","engine","ejs"],version:"2.5.6",author:"Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",contributors:["Timothy Gu <timothygu99@gmail.com> (https://timothygu.github.io)"],license:"Apache-2.0",main:"./lib/ejs.js",repository:{type:"git",url:"git://github.com/mde/ejs.git"},bugs:"https://github.com/mde/ejs/issues",homepage:"https://github.com/mde/ejs",dependencies:{},devDependencies:{browserify:"^13.0.1",eslint:"^3.0.0","git-directory-deploy":"^1.5.1",istanbul:"~0.4.3",jake:"^8.0.0",jsdoc:"^3.4.0","lru-cache":"^4.0.1",mocha:"^3.0.2","uglify-js":"^2.6.2"},engines:{node:">=0.10.0"},scripts:{test:"jake test",lint:'eslint "**/*.js" Jakefile',coverage:"istanbul cover node_modules/mocha/bin/_mocha",doc:"jake doc",devdoc:"jake doc[dev]"}}},{}]},{},[1])(1)});
1 +/*
2 + * EJS Embedded JavaScript templates
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +'use strict';
20 +
21 +/**
22 + * @file Embedded JavaScript templating engine. {@link http://ejs.co}
23 + * @author Matthew Eernisse <mde@fleegix.org>
24 + * @author Tiancheng "Timothy" Gu <timothygu99@gmail.com>
25 + * @project EJS
26 + * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0}
27 + */
28 +
29 +/**
30 + * EJS internal functions.
31 + *
32 + * Technically this "module" lies in the same file as {@link module:ejs}, for
33 + * the sake of organization all the private functions re grouped into this
34 + * module.
35 + *
36 + * @module ejs-internal
37 + * @private
38 + */
39 +
40 +/**
41 + * Embedded JavaScript templating engine.
42 + *
43 + * @module ejs
44 + * @public
45 + */
46 +
47 +var fs = require('fs');
48 +var path = require('path');
49 +var utils = require('./utils');
50 +
51 +var scopeOptionWarned = false;
52 +var _VERSION_STRING = require('../package.json').version;
53 +var _DEFAULT_DELIMITER = '%';
54 +var _DEFAULT_LOCALS_NAME = 'locals';
55 +var _NAME = 'ejs';
56 +var _REGEX_STRING = '(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)';
57 +var _OPTS = ['delimiter', 'scope', 'context', 'debug', 'compileDebug',
58 + 'client', '_with', 'rmWhitespace', 'strict', 'filename'];
59 +// We don't allow 'cache' option to be passed in the data obj
60 +// for the normal `render` call, but this is where Express puts it
61 +// so we make an exception for `renderFile`
62 +var _OPTS_EXPRESS = _OPTS.concat('cache');
63 +var _BOM = /^\uFEFF/;
64 +
65 +/**
66 + * EJS template function cache. This can be a LRU object from lru-cache NPM
67 + * module. By default, it is {@link module:utils.cache}, a simple in-process
68 + * cache that grows continuously.
69 + *
70 + * @type {Cache}
71 + */
72 +
73 +exports.cache = utils.cache;
74 +
75 +/**
76 + * Custom file loader. Useful for template preprocessing or restricting access
77 + * to a certain part of the filesystem.
78 + *
79 + * @type {fileLoader}
80 + */
81 +
82 +exports.fileLoader = fs.readFileSync;
83 +
84 +/**
85 + * Name of the object containing the locals.
86 + *
87 + * This variable is overridden by {@link Options}`.localsName` if it is not
88 + * `undefined`.
89 + *
90 + * @type {String}
91 + * @public
92 + */
93 +
94 +exports.localsName = _DEFAULT_LOCALS_NAME;
95 +
96 +/**
97 + * Get the path to the included file from the parent file path and the
98 + * specified path.
99 + *
100 + * @param {String} name specified path
101 + * @param {String} filename parent file path
102 + * @param {Boolean} isDir parent file path whether is directory
103 + * @return {String}
104 + */
105 +exports.resolveInclude = function(name, filename, isDir) {
106 + var dirname = path.dirname;
107 + var extname = path.extname;
108 + var resolve = path.resolve;
109 + var includePath = resolve(isDir ? filename : dirname(filename), name);
110 + var ext = extname(name);
111 + if (!ext) {
112 + includePath += '.ejs';
113 + }
114 + return includePath;
115 +};
116 +
117 +/**
118 + * Get the path to the included file by Options
119 + *
120 + * @param {String} path specified path
121 + * @param {Options} options compilation options
122 + * @return {String}
123 + */
124 +function getIncludePath(path, options) {
125 + var includePath;
126 + var filePath;
127 + var views = options.views;
128 +
129 + // Abs path
130 + if (path.charAt(0) == '/') {
131 + includePath = exports.resolveInclude(path.replace(/^\/*/,''), options.root || '/', true);
132 + }
133 + // Relative paths
134 + else {
135 + // Look relative to a passed filename first
136 + if (options.filename) {
137 + filePath = exports.resolveInclude(path, options.filename);
138 + if (fs.existsSync(filePath)) {
139 + includePath = filePath;
140 + }
141 + }
142 + // Then look in any views directories
143 + if (!includePath) {
144 + if (Array.isArray(views) && views.some(function (v) {
145 + filePath = exports.resolveInclude(path, v, true);
146 + return fs.existsSync(filePath);
147 + })) {
148 + includePath = filePath;
149 + }
150 + }
151 + if (!includePath) {
152 + throw new Error('Could not find include include file.');
153 + }
154 + }
155 + return includePath;
156 +}
157 +
158 +/**
159 + * Get the template from a string or a file, either compiled on-the-fly or
160 + * read from cache (if enabled), and cache the template if needed.
161 + *
162 + * If `template` is not set, the file specified in `options.filename` will be
163 + * read.
164 + *
165 + * If `options.cache` is true, this function reads the file from
166 + * `options.filename` so it must be set prior to calling this function.
167 + *
168 + * @memberof module:ejs-internal
169 + * @param {Options} options compilation options
170 + * @param {String} [template] template source
171 + * @return {(TemplateFunction|ClientFunction)}
172 + * Depending on the value of `options.client`, either type might be returned.
173 + * @static
174 + */
175 +
176 +function handleCache(options, template) {
177 + var func;
178 + var filename = options.filename;
179 + var hasTemplate = arguments.length > 1;
180 +
181 + if (options.cache) {
182 + if (!filename) {
183 + throw new Error('cache option requires a filename');
184 + }
185 + func = exports.cache.get(filename);
186 + if (func) {
187 + return func;
188 + }
189 + if (!hasTemplate) {
190 + template = fileLoader(filename).toString().replace(_BOM, '');
191 + }
192 + }
193 + else if (!hasTemplate) {
194 + // istanbul ignore if: should not happen at all
195 + if (!filename) {
196 + throw new Error('Internal EJS error: no file name or template '
197 + + 'provided');
198 + }
199 + template = fileLoader(filename).toString().replace(_BOM, '');
200 + }
201 + func = exports.compile(template, options);
202 + if (options.cache) {
203 + exports.cache.set(filename, func);
204 + }
205 + return func;
206 +}
207 +
208 +/**
209 + * Try calling handleCache with the given options and data and call the
210 + * callback with the result. If an error occurs, call the callback with
211 + * the error. Used by renderFile().
212 + *
213 + * @memberof module:ejs-internal
214 + * @param {Options} options compilation options
215 + * @param {Object} data template data
216 + * @param {RenderFileCallback} cb callback
217 + * @static
218 + */
219 +
220 +function tryHandleCache(options, data, cb) {
221 + var result;
222 + try {
223 + result = handleCache(options)(data);
224 + }
225 + catch (err) {
226 + return cb(err);
227 + }
228 + return cb(null, result);
229 +}
230 +
231 +/**
232 + * fileLoader is independent
233 + *
234 + * @param {String} filePath ejs file path.
235 + * @return {String} The contents of the specified file.
236 + * @static
237 + */
238 +
239 +function fileLoader(filePath){
240 + return exports.fileLoader(filePath);
241 +}
242 +
243 +/**
244 + * Get the template function.
245 + *
246 + * If `options.cache` is `true`, then the template is cached.
247 + *
248 + * @memberof module:ejs-internal
249 + * @param {String} path path for the specified file
250 + * @param {Options} options compilation options
251 + * @return {(TemplateFunction|ClientFunction)}
252 + * Depending on the value of `options.client`, either type might be returned
253 + * @static
254 + */
255 +
256 +function includeFile(path, options) {
257 + var opts = utils.shallowCopy({}, options);
258 + opts.filename = getIncludePath(path, opts);
259 + return handleCache(opts);
260 +}
261 +
262 +/**
263 + * Get the JavaScript source of an included file.
264 + *
265 + * @memberof module:ejs-internal
266 + * @param {String} path path for the specified file
267 + * @param {Options} options compilation options
268 + * @return {Object}
269 + * @static
270 + */
271 +
272 +function includeSource(path, options) {
273 + var opts = utils.shallowCopy({}, options);
274 + var includePath;
275 + var template;
276 + includePath = getIncludePath(path, opts);
277 + template = fileLoader(includePath).toString().replace(_BOM, '');
278 + opts.filename = includePath;
279 + var templ = new Template(template, opts);
280 + templ.generateSource();
281 + return {
282 + source: templ.source,
283 + filename: includePath,
284 + template: template
285 + };
286 +}
287 +
288 +/**
289 + * Re-throw the given `err` in context to the `str` of ejs, `filename`, and
290 + * `lineno`.
291 + *
292 + * @implements RethrowCallback
293 + * @memberof module:ejs-internal
294 + * @param {Error} err Error object
295 + * @param {String} str EJS source
296 + * @param {String} filename file name of the EJS file
297 + * @param {String} lineno line number of the error
298 + * @static
299 + */
300 +
301 +function rethrow(err, str, flnm, lineno, esc){
302 + var lines = str.split('\n');
303 + var start = Math.max(lineno - 3, 0);
304 + var end = Math.min(lines.length, lineno + 3);
305 + var filename = esc(flnm); // eslint-disable-line
306 + // Error context
307 + var context = lines.slice(start, end).map(function (line, i){
308 + var curr = i + start + 1;
309 + return (curr == lineno ? ' >> ' : ' ')
310 + + curr
311 + + '| '
312 + + line;
313 + }).join('\n');
314 +
315 + // Alter exception message
316 + err.path = filename;
317 + err.message = (filename || 'ejs') + ':'
318 + + lineno + '\n'
319 + + context + '\n\n'
320 + + err.message;
321 +
322 + throw err;
323 +}
324 +
325 +function stripSemi(str){
326 + return str.replace(/;(\s*$)/, '$1');
327 +}
328 +
329 +/**
330 + * Compile the given `str` of ejs into a template function.
331 + *
332 + * @param {String} template EJS template
333 + *
334 + * @param {Options} opts compilation options
335 + *
336 + * @return {(TemplateFunction|ClientFunction)}
337 + * Depending on the value of `opts.client`, either type might be returned.
338 + * @public
339 + */
340 +
341 +exports.compile = function compile(template, opts) {
342 + var templ;
343 +
344 + // v1 compat
345 + // 'scope' is 'context'
346 + // FIXME: Remove this in a future version
347 + if (opts && opts.scope) {
348 + if (!scopeOptionWarned){
349 + console.warn('`scope` option is deprecated and will be removed in EJS 3');
350 + scopeOptionWarned = true;
351 + }
352 + if (!opts.context) {
353 + opts.context = opts.scope;
354 + }
355 + delete opts.scope;
356 + }
357 + templ = new Template(template, opts);
358 + return templ.compile();
359 +};
360 +
361 +/**
362 + * Render the given `template` of ejs.
363 + *
364 + * If you would like to include options but not data, you need to explicitly
365 + * call this function with `data` being an empty object or `null`.
366 + *
367 + * @param {String} template EJS template
368 + * @param {Object} [data={}] template data
369 + * @param {Options} [opts={}] compilation and rendering options
370 + * @return {String}
371 + * @public
372 + */
373 +
374 +exports.render = function (template, d, o) {
375 + var data = d || {};
376 + var opts = o || {};
377 +
378 + // No options object -- if there are optiony names
379 + // in the data, copy them to options
380 + if (arguments.length == 2) {
381 + utils.shallowCopyFromList(opts, data, _OPTS);
382 + }
383 +
384 + return handleCache(opts, template)(data);
385 +};
386 +
387 +/**
388 + * Render an EJS file at the given `path` and callback `cb(err, str)`.
389 + *
390 + * If you would like to include options but not data, you need to explicitly
391 + * call this function with `data` being an empty object or `null`.
392 + *
393 + * @param {String} path path to the EJS file
394 + * @param {Object} [data={}] template data
395 + * @param {Options} [opts={}] compilation and rendering options
396 + * @param {RenderFileCallback} cb callback
397 + * @public
398 + */
399 +
400 +exports.renderFile = function () {
401 + var filename = arguments[0];
402 + var cb = arguments[arguments.length - 1];
403 + var opts = {filename: filename};
404 + var data;
405 +
406 + if (arguments.length > 2) {
407 + data = arguments[1];
408 +
409 + // No options object -- if there are optiony names
410 + // in the data, copy them to options
411 + if (arguments.length === 3) {
412 + // Express 4
413 + if (data.settings) {
414 + if (data.settings['view options']) {
415 + utils.shallowCopyFromList(opts, data.settings['view options'], _OPTS_EXPRESS);
416 + }
417 + if (data.settings.views) {
418 + opts.views = data.settings.views;
419 + }
420 + }
421 + // Express 3 and lower
422 + else {
423 + utils.shallowCopyFromList(opts, data, _OPTS_EXPRESS);
424 + }
425 + }
426 + else {
427 + // Use shallowCopy so we don't pollute passed in opts obj with new vals
428 + utils.shallowCopy(opts, arguments[2]);
429 + }
430 +
431 + opts.filename = filename;
432 + }
433 + else {
434 + data = {};
435 + }
436 +
437 + return tryHandleCache(opts, data, cb);
438 +};
439 +
440 +/**
441 + * Clear intermediate JavaScript cache. Calls {@link Cache#reset}.
442 + * @public
443 + */
444 +
445 +exports.clearCache = function () {
446 + exports.cache.reset();
447 +};
448 +
449 +function Template(text, opts) {
450 + opts = opts || {};
451 + var options = {};
452 + this.templateText = text;
453 + this.mode = null;
454 + this.truncate = false;
455 + this.currentLine = 1;
456 + this.source = '';
457 + this.dependencies = [];
458 + options.client = opts.client || false;
459 + options.escapeFunction = opts.escape || utils.escapeXML;
460 + options.compileDebug = opts.compileDebug !== false;
461 + options.debug = !!opts.debug;
462 + options.filename = opts.filename;
463 + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER;
464 + options.strict = opts.strict || false;
465 + options.context = opts.context;
466 + options.cache = opts.cache || false;
467 + options.rmWhitespace = opts.rmWhitespace;
468 + options.root = opts.root;
469 + options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME;
470 + options.views = opts.views;
471 +
472 + if (options.strict) {
473 + options._with = false;
474 + }
475 + else {
476 + options._with = typeof opts._with != 'undefined' ? opts._with : true;
477 + }
478 +
479 + this.opts = options;
480 +
481 + this.regex = this.createRegex();
482 +}
483 +
484 +Template.modes = {
485 + EVAL: 'eval',
486 + ESCAPED: 'escaped',
487 + RAW: 'raw',
488 + COMMENT: 'comment',
489 + LITERAL: 'literal'
490 +};
491 +
492 +Template.prototype = {
493 + createRegex: function () {
494 + var str = _REGEX_STRING;
495 + var delim = utils.escapeRegExpChars(this.opts.delimiter);
496 + str = str.replace(/%/g, delim);
497 + return new RegExp(str);
498 + },
499 +
500 + compile: function () {
501 + var src;
502 + var fn;
503 + var opts = this.opts;
504 + var prepended = '';
505 + var appended = '';
506 + var escapeFn = opts.escapeFunction;
507 +
508 + if (!this.source) {
509 + this.generateSource();
510 + prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n';
511 + if (opts._with !== false) {
512 + prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
513 + appended += ' }' + '\n';
514 + }
515 + appended += ' return __output.join("");' + '\n';
516 + this.source = prepended + this.source + appended;
517 + }
518 +
519 + if (opts.compileDebug) {
520 + src = 'var __line = 1' + '\n'
521 + + ' , __lines = ' + JSON.stringify(this.templateText) + '\n'
522 + + ' , __filename = ' + (opts.filename ?
523 + JSON.stringify(opts.filename) : 'undefined') + ';' + '\n'
524 + + 'try {' + '\n'
525 + + this.source
526 + + '} catch (e) {' + '\n'
527 + + ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n'
528 + + '}' + '\n';
529 + }
530 + else {
531 + src = this.source;
532 + }
533 +
534 + if (opts.client) {
535 + src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src;
536 + if (opts.compileDebug) {
537 + src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src;
538 + }
539 + }
540 +
541 + if (opts.strict) {
542 + src = '"use strict";\n' + src;
543 + }
544 + if (opts.debug) {
545 + console.log(src);
546 + }
547 +
548 + try {
549 + fn = new Function(opts.localsName + ', escapeFn, include, rethrow', src);
550 + }
551 + catch(e) {
552 + // istanbul ignore else
553 + if (e instanceof SyntaxError) {
554 + if (opts.filename) {
555 + e.message += ' in ' + opts.filename;
556 + }
557 + e.message += ' while compiling ejs\n\n';
558 + e.message += 'If the above error is not helpful, you may want to try EJS-Lint:\n';
559 + e.message += 'https://github.com/RyanZim/EJS-Lint';
560 + }
561 + throw e;
562 + }
563 +
564 + if (opts.client) {
565 + fn.dependencies = this.dependencies;
566 + return fn;
567 + }
568 +
569 + // Return a callable function which will execute the function
570 + // created by the source-code, with the passed data as locals
571 + // Adds a local `include` function which allows full recursive include
572 + var returnedFn = function (data) {
573 + var include = function (path, includeData) {
574 + var d = utils.shallowCopy({}, data);
575 + if (includeData) {
576 + d = utils.shallowCopy(d, includeData);
577 + }
578 + return includeFile(path, opts)(d);
579 + };
580 + return fn.apply(opts.context, [data || {}, escapeFn, include, rethrow]);
581 + };
582 + returnedFn.dependencies = this.dependencies;
583 + return returnedFn;
584 + },
585 +
586 + generateSource: function () {
587 + var opts = this.opts;
588 +
589 + if (opts.rmWhitespace) {
590 + // Have to use two separate replace here as `^` and `$` operators don't
591 + // work well with `\r`.
592 + this.templateText =
593 + this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, '');
594 + }
595 +
596 + // Slurp spaces and tabs before <%_ and after _%>
597 + this.templateText =
598 + this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>');
599 +
600 + var self = this;
601 + var matches = this.parseTemplateText();
602 + var d = this.opts.delimiter;
603 +
604 + if (matches && matches.length) {
605 + matches.forEach(function (line, index) {
606 + var opening;
607 + var closing;
608 + var include;
609 + var includeOpts;
610 + var includeObj;
611 + var includeSrc;
612 + // If this is an opening tag, check for closing tags
613 + // FIXME: May end up with some false positives here
614 + // Better to store modes as k/v with '<' + delimiter as key
615 + // Then this can simply check against the map
616 + if ( line.indexOf('<' + d) === 0 // If it is a tag
617 + && line.indexOf('<' + d + d) !== 0) { // and is not escaped
618 + closing = matches[index + 2];
619 + if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) {
620 + throw new Error('Could not find matching close tag for "' + line + '".');
621 + }
622 + }
623 + // HACK: backward-compat `include` preprocessor directives
624 + if ((include = line.match(/^\s*include\s+(\S+)/))) {
625 + opening = matches[index - 1];
626 + // Must be in EVAL or RAW mode
627 + if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) {
628 + includeOpts = utils.shallowCopy({}, self.opts);
629 + includeObj = includeSource(include[1], includeOpts);
630 + if (self.opts.compileDebug) {
631 + includeSrc =
632 + ' ; (function(){' + '\n'
633 + + ' var __line = 1' + '\n'
634 + + ' , __lines = ' + JSON.stringify(includeObj.template) + '\n'
635 + + ' , __filename = ' + JSON.stringify(includeObj.filename) + ';' + '\n'
636 + + ' try {' + '\n'
637 + + includeObj.source
638 + + ' } catch (e) {' + '\n'
639 + + ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n'
640 + + ' }' + '\n'
641 + + ' ; }).call(this)' + '\n';
642 + }else{
643 + includeSrc = ' ; (function(){' + '\n' + includeObj.source +
644 + ' ; }).call(this)' + '\n';
645 + }
646 + self.source += includeSrc;
647 + self.dependencies.push(exports.resolveInclude(include[1],
648 + includeOpts.filename));
649 + return;
650 + }
651 + }
652 + self.scanLine(line);
653 + });
654 + }
655 +
656 + },
657 +
658 + parseTemplateText: function () {
659 + var str = this.templateText;
660 + var pat = this.regex;
661 + var result = pat.exec(str);
662 + var arr = [];
663 + var firstPos;
664 +
665 + while (result) {
666 + firstPos = result.index;
667 +
668 + if (firstPos !== 0) {
669 + arr.push(str.substring(0, firstPos));
670 + str = str.slice(firstPos);
671 + }
672 +
673 + arr.push(result[0]);
674 + str = str.slice(result[0].length);
675 + result = pat.exec(str);
676 + }
677 +
678 + if (str) {
679 + arr.push(str);
680 + }
681 +
682 + return arr;
683 + },
684 +
685 + _addOutput: function (line) {
686 + if (this.truncate) {
687 + // Only replace single leading linebreak in the line after
688 + // -%> tag -- this is the single, trailing linebreak
689 + // after the tag that the truncation mode replaces
690 + // Handle Win / Unix / old Mac linebreaks -- do the \r\n
691 + // combo first in the regex-or
692 + line = line.replace(/^(?:\r\n|\r|\n)/, '');
693 + this.truncate = false;
694 + }
695 + else if (this.opts.rmWhitespace) {
696 + // rmWhitespace has already removed trailing spaces, just need
697 + // to remove linebreaks
698 + line = line.replace(/^\n/, '');
699 + }
700 + if (!line) {
701 + return line;
702 + }
703 +
704 + // Preserve literal slashes
705 + line = line.replace(/\\/g, '\\\\');
706 +
707 + // Convert linebreaks
708 + line = line.replace(/\n/g, '\\n');
709 + line = line.replace(/\r/g, '\\r');
710 +
711 + // Escape double-quotes
712 + // - this will be the delimiter during execution
713 + line = line.replace(/"/g, '\\"');
714 + this.source += ' ; __append("' + line + '")' + '\n';
715 + },
716 +
717 + scanLine: function (line) {
718 + var self = this;
719 + var d = this.opts.delimiter;
720 + var newLineCount = 0;
721 +
722 + newLineCount = (line.split('\n').length - 1);
723 +
724 + switch (line) {
725 + case '<' + d:
726 + case '<' + d + '_':
727 + this.mode = Template.modes.EVAL;
728 + break;
729 + case '<' + d + '=':
730 + this.mode = Template.modes.ESCAPED;
731 + break;
732 + case '<' + d + '-':
733 + this.mode = Template.modes.RAW;
734 + break;
735 + case '<' + d + '#':
736 + this.mode = Template.modes.COMMENT;
737 + break;
738 + case '<' + d + d:
739 + this.mode = Template.modes.LITERAL;
740 + this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n';
741 + break;
742 + case d + d + '>':
743 + this.mode = Template.modes.LITERAL;
744 + this.source += ' ; __append("' + line.replace(d + d + '>', d + '>') + '")' + '\n';
745 + break;
746 + case d + '>':
747 + case '-' + d + '>':
748 + case '_' + d + '>':
749 + if (this.mode == Template.modes.LITERAL) {
750 + this._addOutput(line);
751 + }
752 +
753 + this.mode = null;
754 + this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0;
755 + break;
756 + default:
757 + // In script mode, depends on type of tag
758 + if (this.mode) {
759 + // If '//' is found without a line break, add a line break.
760 + switch (this.mode) {
761 + case Template.modes.EVAL:
762 + case Template.modes.ESCAPED:
763 + case Template.modes.RAW:
764 + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) {
765 + line += '\n';
766 + }
767 + }
768 + switch (this.mode) {
769 + // Just executing code
770 + case Template.modes.EVAL:
771 + this.source += ' ; ' + line + '\n';
772 + break;
773 + // Exec, esc, and output
774 + case Template.modes.ESCAPED:
775 + this.source += ' ; __append(escapeFn(' + stripSemi(line) + '))' + '\n';
776 + break;
777 + // Exec and output
778 + case Template.modes.RAW:
779 + this.source += ' ; __append(' + stripSemi(line) + ')' + '\n';
780 + break;
781 + case Template.modes.COMMENT:
782 + // Do nothing
783 + break;
784 + // Literal <%% mode, append as raw output
785 + case Template.modes.LITERAL:
786 + this._addOutput(line);
787 + break;
788 + }
789 + }
790 + // In string mode, just add the output
791 + else {
792 + this._addOutput(line);
793 + }
794 + }
795 +
796 + if (self.opts.compileDebug && newLineCount) {
797 + this.currentLine += newLineCount;
798 + this.source += ' ; __line = ' + this.currentLine + '\n';
799 + }
800 + }
801 +};
802 +
803 +/**
804 + * Escape characters reserved in XML.
805 + *
806 + * This is simply an export of {@link module:utils.escapeXML}.
807 + *
808 + * If `markup` is `undefined` or `null`, the empty string is returned.
809 + *
810 + * @param {String} markup Input string
811 + * @return {String} Escaped string
812 + * @public
813 + * @func
814 + * */
815 +exports.escapeXML = utils.escapeXML;
816 +
817 +/**
818 + * Express.js support.
819 + *
820 + * This is an alias for {@link module:ejs.renderFile}, in order to support
821 + * Express.js out-of-the-box.
822 + *
823 + * @func
824 + */
825 +
826 +exports.__express = exports.renderFile;
827 +
828 +// Add require support
829 +/* istanbul ignore else */
830 +if (require.extensions) {
831 + require.extensions['.ejs'] = function (module, flnm) {
832 + var filename = flnm || /* istanbul ignore next */ module.filename;
833 + var options = {
834 + filename: filename,
835 + client: true
836 + };
837 + var template = fileLoader(filename).toString();
838 + var fn = exports.compile(template, options);
839 + module._compile('module.exports = ' + fn.toString() + ';', filename);
840 + };
841 +}
842 +
843 +/**
844 + * Version of EJS.
845 + *
846 + * @readonly
847 + * @type {String}
848 + * @public
849 + */
850 +
851 +exports.VERSION = _VERSION_STRING;
852 +
853 +/**
854 + * Name for detection of EJS.
855 + *
856 + * @readonly
857 + * @type {String}
858 + * @public
859 + */
860 +
861 +exports.name = _NAME;
862 +
863 +/* istanbul ignore if */
864 +if (typeof window != 'undefined') {
865 + window.ejs = exports;
866 +}
1 +/*
2 + * EJS Embedded JavaScript templates
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +/**
20 + * Private utility functions
21 + * @module utils
22 + * @private
23 + */
24 +
25 +'use strict';
26 +
27 +var regExpChars = /[|\\{}()[\]^$+*?.]/g;
28 +
29 +/**
30 + * Escape characters reserved in regular expressions.
31 + *
32 + * If `string` is `undefined` or `null`, the empty string is returned.
33 + *
34 + * @param {String} string Input string
35 + * @return {String} Escaped string
36 + * @static
37 + * @private
38 + */
39 +exports.escapeRegExpChars = function (string) {
40 + // istanbul ignore if
41 + if (!string) {
42 + return '';
43 + }
44 + return String(string).replace(regExpChars, '\\$&');
45 +};
46 +
47 +var _ENCODE_HTML_RULES = {
48 + '&': '&amp;',
49 + '<': '&lt;',
50 + '>': '&gt;',
51 + '"': '&#34;',
52 + "'": '&#39;'
53 +};
54 +var _MATCH_HTML = /[&<>\'"]/g;
55 +
56 +function encode_char(c) {
57 + return _ENCODE_HTML_RULES[c] || c;
58 +}
59 +
60 +/**
61 + * Stringified version of constants used by {@link module:utils.escapeXML}.
62 + *
63 + * It is used in the process of generating {@link ClientFunction}s.
64 + *
65 + * @readonly
66 + * @type {String}
67 + */
68 +
69 +var escapeFuncStr =
70 + 'var _ENCODE_HTML_RULES = {\n'
71 ++ ' "&": "&amp;"\n'
72 ++ ' , "<": "&lt;"\n'
73 ++ ' , ">": "&gt;"\n'
74 ++ ' , \'"\': "&#34;"\n'
75 ++ ' , "\'": "&#39;"\n'
76 ++ ' }\n'
77 ++ ' , _MATCH_HTML = /[&<>\'"]/g;\n'
78 ++ 'function encode_char(c) {\n'
79 ++ ' return _ENCODE_HTML_RULES[c] || c;\n'
80 ++ '};\n';
81 +
82 +/**
83 + * Escape characters reserved in XML.
84 + *
85 + * If `markup` is `undefined` or `null`, the empty string is returned.
86 + *
87 + * @implements {EscapeCallback}
88 + * @param {String} markup Input string
89 + * @return {String} Escaped string
90 + * @static
91 + * @private
92 + */
93 +
94 +exports.escapeXML = function (markup) {
95 + return markup == undefined
96 + ? ''
97 + : String(markup)
98 + .replace(_MATCH_HTML, encode_char);
99 +};
100 +exports.escapeXML.toString = function () {
101 + return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr;
102 +};
103 +
104 +/**
105 + * Naive copy of properties from one object to another.
106 + * Does not recurse into non-scalar properties
107 + * Does not check to see if the property has a value before copying
108 + *
109 + * @param {Object} to Destination object
110 + * @param {Object} from Source object
111 + * @return {Object} Destination object
112 + * @static
113 + * @private
114 + */
115 +exports.shallowCopy = function (to, from) {
116 + from = from || {};
117 + for (var p in from) {
118 + to[p] = from[p];
119 + }
120 + return to;
121 +};
122 +
123 +/**
124 + * Naive copy of a list of key names, from one object to another.
125 + * Only copies property if it is actually defined
126 + * Does not recurse into non-scalar properties
127 + *
128 + * @param {Object} to Destination object
129 + * @param {Object} from Source object
130 + * @param {Array} list List of properties to copy
131 + * @return {Object} Destination object
132 + * @static
133 + * @private
134 + */
135 +exports.shallowCopyFromList = function (to, from, list) {
136 + for (var i = 0; i < list.length; i++) {
137 + var p = list[i];
138 + if (typeof from[p] != 'undefined') {
139 + to[p] = from[p];
140 + }
141 + }
142 + return to;
143 +};
144 +
145 +/**
146 + * Simple in-process cache implementation. Does not implement limits of any
147 + * sort.
148 + *
149 + * @implements Cache
150 + * @static
151 + * @private
152 + */
153 +exports.cache = {
154 + _data: {},
155 + set: function (key, val) {
156 + this._data[key] = val;
157 + },
158 + get: function (key) {
159 + return this._data[key];
160 + },
161 + reset: function () {
162 + this._data = {};
163 + }
164 +};
1 +{
2 + "_from": "ejs@~2.5.7",
3 + "_id": "ejs@2.5.7",
4 + "_inBundle": false,
5 + "_integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=",
6 + "_location": "/ejs",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "ejs@~2.5.7",
12 + "name": "ejs",
13 + "escapedName": "ejs",
14 + "rawSpec": "~2.5.7",
15 + "saveSpec": null,
16 + "fetchSpec": "~2.5.7"
17 + },
18 + "_requiredBy": [
19 + "/"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz",
22 + "_shasum": "cc872c168880ae3c7189762fd5ffc00896c9518a",
23 + "_spec": "ejs@~2.5.7",
24 + "_where": "/home/ubuntu/OpenSource_Project",
25 + "author": {
26 + "name": "Matthew Eernisse",
27 + "email": "mde@fleegix.org",
28 + "url": "http://fleegix.org"
29 + },
30 + "bugs": {
31 + "url": "https://github.com/mde/ejs/issues"
32 + },
33 + "bundleDependencies": false,
34 + "contributors": [
35 + {
36 + "name": "Timothy Gu",
37 + "email": "timothygu99@gmail.com",
38 + "url": "https://timothygu.github.io"
39 + }
40 + ],
41 + "dependencies": {},
42 + "deprecated": false,
43 + "description": "Embedded JavaScript templates",
44 + "devDependencies": {
45 + "browserify": "^13.0.1",
46 + "eslint": "^3.0.0",
47 + "git-directory-deploy": "^1.5.1",
48 + "istanbul": "~0.4.3",
49 + "jake": "^8.0.0",
50 + "jsdoc": "^3.4.0",
51 + "lru-cache": "^4.0.1",
52 + "mocha": "^3.0.2",
53 + "uglify-js": "^2.6.2"
54 + },
55 + "engines": {
56 + "node": ">=0.10.0"
57 + },
58 + "homepage": "https://github.com/mde/ejs",
59 + "keywords": [
60 + "template",
61 + "engine",
62 + "ejs"
63 + ],
64 + "license": "Apache-2.0",
65 + "main": "./lib/ejs.js",
66 + "name": "ejs",
67 + "repository": {
68 + "type": "git",
69 + "url": "git://github.com/mde/ejs.git"
70 + },
71 + "scripts": {
72 + "coverage": "istanbul cover node_modules/mocha/bin/_mocha",
73 + "devdoc": "jake doc[dev]",
74 + "doc": "jake doc",
75 + "lint": "eslint \"**/*.js\" Jakefile",
76 + "test": "jake test"
77 + },
78 + "version": "2.5.7"
79 +}
1 +1.9.0 / 2017-09-26
2 +==================
3 +
4 + * Use `res.headersSent` when available
5 + * deps: basic-auth@~2.0.0
6 + - Use `safe-buffer` for improved Buffer API
7 + * deps: debug@2.6.9
8 + * deps: depd@~1.1.1
9 + - Remove unnecessary `Buffer` loading
10 +
11 +1.8.2 / 2017-05-23
12 +==================
13 +
14 + * deps: debug@2.6.8
15 + - Fix `DEBUG_MAX_ARRAY_LENGTH`
16 + - deps: ms@2.0.0
17 +
18 +1.8.1 / 2017-02-04
19 +==================
20 +
21 + * deps: debug@2.6.1
22 + - Fix deprecation messages in WebStorm and other editors
23 + - Undeprecate `DEBUG_FD` set to `1` or `2`
24 +
25 +1.8.0 / 2017-02-04
26 +==================
27 +
28 + * Fix sending unnecessary `undefined` argument to token functions
29 + * deps: basic-auth@~1.1.0
30 + * deps: debug@2.6.0
31 + - Allow colors in workers
32 + - Deprecated `DEBUG_FD` environment variable
33 + - Fix error when running under React Native
34 + - Use same color for same namespace
35 + - deps: ms@0.7.2
36 + * perf: enable strict mode in compiled functions
37 +
38 +1.7.0 / 2016-02-18
39 +==================
40 +
41 + * Add `digits` argument to `response-time` token
42 + * deps: depd@~1.1.0
43 + - Enable strict mode in more places
44 + - Support web browser loading
45 + * deps: on-headers@~1.0.1
46 + - perf: enable strict mode
47 +
48 +1.6.1 / 2015-07-03
49 +==================
50 +
51 + * deps: basic-auth@~1.0.3
52 +
53 +1.6.0 / 2015-06-12
54 +==================
55 +
56 + * Add `morgan.compile(format)` export
57 + * Do not color 1xx status codes in `dev` format
58 + * Fix `response-time` token to not include response latency
59 + * Fix `status` token incorrectly displaying before response in `dev` format
60 + * Fix token return values to be `undefined` or a string
61 + * Improve representation of multiple headers in `req` and `res` tokens
62 + * Use `res.getHeader` in `res` token
63 + * deps: basic-auth@~1.0.2
64 + - perf: enable strict mode
65 + - perf: hoist regular expression
66 + - perf: parse with regular expressions
67 + - perf: remove argument reassignment
68 + * deps: on-finished@~2.3.0
69 + - Add defined behavior for HTTP `CONNECT` requests
70 + - Add defined behavior for HTTP `Upgrade` requests
71 + - deps: ee-first@1.1.1
72 + * pref: enable strict mode
73 + * pref: reduce function closure scopes
74 + * pref: remove dynamic compile on every request for `dev` format
75 + * pref: remove an argument reassignment
76 + * pref: skip function call without `skip` option
77 +
78 +1.5.3 / 2015-05-10
79 +==================
80 +
81 + * deps: basic-auth@~1.0.1
82 + * deps: debug@~2.2.0
83 + - deps: ms@0.7.1
84 + * deps: depd@~1.0.1
85 + * deps: on-finished@~2.2.1
86 + - Fix `isFinished(req)` when data buffered
87 +
88 +1.5.2 / 2015-03-15
89 +==================
90 +
91 + * deps: debug@~2.1.3
92 + - Fix high intensity foreground color for bold
93 + - deps: ms@0.7.0
94 +
95 +1.5.1 / 2014-12-31
96 +==================
97 +
98 + * deps: debug@~2.1.1
99 + * deps: on-finished@~2.2.0
100 +
101 +1.5.0 / 2014-11-06
102 +==================
103 +
104 + * Add multiple date formats
105 + - `clf` for the common log format
106 + - `iso` for the common ISO 8601 date time format
107 + - `web` for the common RFC 1123 date time format
108 + * Deprecate `buffer` option
109 + * Fix date format in `common` and `combined` formats
110 + * Fix token arguments to accept values with `"`
111 +
112 +1.4.1 / 2014-10-22
113 +==================
114 +
115 + * deps: on-finished@~2.1.1
116 + - Fix handling of pipelined requests
117 +
118 +1.4.0 / 2014-10-16
119 +==================
120 +
121 + * Add `debug` messages
122 + * deps: depd@~1.0.0
123 +
124 +1.3.2 / 2014-09-27
125 +==================
126 +
127 + * Fix `req.ip` integration when `immediate: false`
128 +
129 +1.3.1 / 2014-09-14
130 +==================
131 +
132 + * Remove un-used `bytes` dependency
133 + * deps: depd@0.4.5
134 +
135 +1.3.0 / 2014-09-01
136 +==================
137 +
138 + * Assert if `format` is not a function or string
139 +
140 +1.2.3 / 2014-08-16
141 +==================
142 +
143 + * deps: on-finished@2.1.0
144 +
145 +1.2.2 / 2014-07-27
146 +==================
147 +
148 + * deps: depd@0.4.4
149 + - Work-around v8 generating empty stack traces
150 +
151 +1.2.1 / 2014-07-26
152 +==================
153 +
154 + * deps: depd@0.4.3
155 + - Fix exception when global `Error.stackTraceLimit` is too low
156 +
157 +1.2.0 / 2014-07-19
158 +==================
159 +
160 + * Add `:remote-user` token
161 + * Add `combined` log format
162 + * Add `common` log format
163 + * Add `morgan(format, options)` function signature
164 + * Deprecate `default` format -- use `combined` format instead
165 + * Deprecate not providing a format
166 + * Remove non-standard grey color from `dev` format
167 +
168 +1.1.1 / 2014-05-20
169 +==================
170 +
171 + * simplify method to get remote address
172 +
173 +1.1.0 / 2014-05-18
174 +==================
175 +
176 + * "dev" format will use same tokens as other formats
177 + * `:response-time` token is now empty when immediate used
178 + * `:response-time` token is now monotonic
179 + * `:response-time` token has precision to 1 μs
180 + * fix `:status` + immediate output in node.js 0.8
181 + * improve `buffer` option to prevent indefinite event loop holding
182 + * deps: bytes@1.0.0
183 + - add negative support
184 +
185 +1.0.1 / 2014-05-04
186 +==================
187 +
188 + * Make buffer unique per morgan instance
189 + * deps: bytes@0.3.0
190 + * added terabyte support
191 +
192 +1.0.0 / 2014-02-08
193 +==================
194 +
195 + * Initial release
1 +(The MIT License)
2 +
3 +Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
4 +Copyright (c) 2014-2017 Douglas Christopher Wilson <doug@somethingdoug.com>
5 +
6 +Permission is hereby granted, free of charge, to any person obtaining
7 +a copy of this software and associated documentation files (the
8 +'Software'), to deal in the Software without restriction, including
9 +without limitation the rights to use, copy, modify, merge, publish,
10 +distribute, sublicense, and/or sell copies of the Software, and to
11 +permit persons to whom the Software is furnished to do so, subject to
12 +the following conditions:
13 +
14 +The above copyright notice and this permission notice shall be
15 +included in all copies or substantial portions of the Software.
16 +
17 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
18 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +# morgan
2 +
3 +[![NPM Version][npm-image]][npm-url]
4 +[![NPM Downloads][downloads-image]][downloads-url]
5 +[![Build Status][travis-image]][travis-url]
6 +[![Test Coverage][coveralls-image]][coveralls-url]
7 +[![Gratipay][gratipay-image]][gratipay-url]
8 +
9 +HTTP request logger middleware for node.js
10 +
11 +> Named after [Dexter](http://en.wikipedia.org/wiki/Dexter_Morgan), a show you should not watch until completion.
12 +
13 +## API
14 +
15 +<!-- eslint-disable no-unused-vars -->
16 +
17 +```js
18 +var morgan = require('morgan')
19 +```
20 +
21 +### morgan(format, options)
22 +
23 +Create a new morgan logger middleware function using the given `format` and `options`.
24 +The `format` argument may be a string of a predefined name (see below for the names),
25 +a string of a format string, or a function that will produce a log entry.
26 +
27 +The `format` function will be called with three arguments `tokens`, `req`, and `res`,
28 +where `tokens` is an object with all defined tokens, `req` is the HTTP request and `res`
29 +is the HTTP response. The function is expected to return a string that will be the log
30 +line, or `undefined` / `null` to skip logging.
31 +
32 +#### Using a predefined format string
33 +
34 +<!-- eslint-disable no-undef -->
35 +
36 +```js
37 +morgan('tiny')
38 +```
39 +
40 +#### Using format string of predefined tokens
41 +
42 +<!-- eslint-disable no-undef -->
43 +
44 +```js
45 +morgan(':method :url :status :res[content-length] - :response-time ms')
46 +```
47 +
48 +#### Using a custom format function
49 +
50 +<!-- eslint-disable no-undef -->
51 +
52 +``` js
53 +morgan(function (tokens, req, res) {
54 + return [
55 + tokens.method(req, res),
56 + tokens.url(req, res),
57 + tokens.status(req, res),
58 + tokens.res(req, res, 'content-length'), '-',
59 + tokens['response-time'](req, res), 'ms'
60 + ].join(' ')
61 +})
62 +```
63 +
64 +#### Options
65 +
66 +Morgan accepts these properties in the options object.
67 +
68 +##### immediate
69 +
70 +Write log line on request instead of response. This means that a requests will
71 +be logged even if the server crashes, _but data from the response (like the
72 +response code, content length, etc.) cannot be logged_.
73 +
74 +##### skip
75 +
76 +Function to determine if logging is skipped, defaults to `false`. This function
77 +will be called as `skip(req, res)`.
78 +
79 +<!-- eslint-disable no-undef -->
80 +
81 +```js
82 +// EXAMPLE: only log error responses
83 +morgan('combined', {
84 + skip: function (req, res) { return res.statusCode < 400 }
85 +})
86 +```
87 +
88 +##### stream
89 +
90 +Output stream for writing log lines, defaults to `process.stdout`.
91 +
92 +#### Predefined Formats
93 +
94 +There are various pre-defined formats provided:
95 +
96 +##### combined
97 +
98 +Standard Apache combined log output.
99 +
100 +```
101 +:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
102 +```
103 +
104 +##### common
105 +
106 +Standard Apache common log output.
107 +
108 +```
109 +:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]
110 +```
111 +
112 +##### dev
113 +
114 +Concise output colored by response status for development use. The `:status`
115 +token will be colored red for server error codes, yellow for client error
116 +codes, cyan for redirection codes, and uncolored for all other codes.
117 +
118 +```
119 +:method :url :status :response-time ms - :res[content-length]
120 +```
121 +
122 +##### short
123 +
124 +Shorter than default, also including response time.
125 +
126 +```
127 +:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
128 +```
129 +
130 +##### tiny
131 +
132 +The minimal output.
133 +
134 +```
135 +:method :url :status :res[content-length] - :response-time ms
136 +```
137 +
138 +#### Tokens
139 +
140 +##### Creating new tokens
141 +
142 +To define a token, simply invoke `morgan.token()` with the name and a callback function.
143 +This callback function is expected to return a string value. The value returned is then
144 +available as ":type" in this case:
145 +
146 +<!-- eslint-disable no-undef -->
147 +
148 +```js
149 +morgan.token('type', function (req, res) { return req.headers['content-type'] })
150 +```
151 +
152 +Calling `morgan.token()` using the same name as an existing token will overwrite that
153 +token definition.
154 +
155 +The token function is expected to be called with the arguments `req` and `res`, representing
156 +the HTTP request and HTTP response. Additionally, the token can accept further arguments of
157 +it's choosing to customize behavior.
158 +
159 +##### :date[format]
160 +
161 +The current date and time in UTC. The available formats are:
162 +
163 + - `clf` for the common log format (`"10/Oct/2000:13:55:36 +0000"`)
164 + - `iso` for the common ISO 8601 date time format (`2000-10-10T13:55:36.000Z`)
165 + - `web` for the common RFC 1123 date time format (`Tue, 10 Oct 2000 13:55:36 GMT`)
166 +
167 +If no format is given, then the default is `web`.
168 +
169 +##### :http-version
170 +
171 +The HTTP version of the request.
172 +
173 +##### :method
174 +
175 +The HTTP method of the request.
176 +
177 +##### :referrer
178 +
179 +The Referrer header of the request. This will use the standard mis-spelled Referer header if exists, otherwise Referrer.
180 +
181 +##### :remote-addr
182 +
183 +The remote address of the request. This will use `req.ip`, otherwise the standard `req.connection.remoteAddress` value (socket address).
184 +
185 +##### :remote-user
186 +
187 +The user authenticated as part of Basic auth for the request.
188 +
189 +##### :req[header]
190 +
191 +The given `header` of the request.
192 +
193 +##### :res[header]
194 +
195 +The given `header` of the response.
196 +
197 +##### :response-time[digits]
198 +
199 +The time between the request coming into `morgan` and when the response
200 +headers are written, in milliseconds.
201 +
202 +The `digits` argument is a number that specifies the number of digits to
203 +include on the number, defaulting to `3`, which provides microsecond precision.
204 +
205 +##### :status
206 +
207 +The status code of the response.
208 +
209 +If the request/response cycle completes before a response was sent to the
210 +client (for example, the TCP socket closed prematurely by a client aborting
211 +the request), then the status will be empty (displayed as `"-"` in the log).
212 +
213 +##### :url
214 +
215 +The URL of the request. This will use `req.originalUrl` if exists, otherwise `req.url`.
216 +
217 +##### :user-agent
218 +
219 +The contents of the User-Agent header of the request.
220 +
221 +### morgan.compile(format)
222 +
223 +Compile a format string into a `format` function for use by `morgan`. A format string
224 +is a string that represents a single log line and can utilize token syntax.
225 +Tokens are references by `:token-name`. If tokens accept arguments, they can
226 +be passed using `[]`, for example: `:token-name[pretty]` would pass the string
227 +`'pretty'` as an argument to the token `token-name`.
228 +
229 +The function returned from `morgan.compile` takes three arguments `tokens`, `req`, and
230 +`res`, where `tokens` is object with all defined tokens, `req` is the HTTP request and
231 +`res` is the HTTP response. The function will return a string that will be the log line,
232 +or `undefined` / `null` to skip logging.
233 +
234 +Normally formats are defined using `morgan.format(name, format)`, but for certain
235 +advanced uses, this compile function is directly available.
236 +
237 +## Examples
238 +
239 +### express/connect
240 +
241 +Simple app that will log all request in the Apache combined format to STDOUT
242 +
243 +```js
244 +var express = require('express')
245 +var morgan = require('morgan')
246 +
247 +var app = express()
248 +
249 +app.use(morgan('combined'))
250 +
251 +app.get('/', function (req, res) {
252 + res.send('hello, world!')
253 +})
254 +```
255 +
256 +### vanilla http server
257 +
258 +Simple app that will log all request in the Apache combined format to STDOUT
259 +
260 +```js
261 +var finalhandler = require('finalhandler')
262 +var http = require('http')
263 +var morgan = require('morgan')
264 +
265 +// create "middleware"
266 +var logger = morgan('combined')
267 +
268 +http.createServer(function (req, res) {
269 + var done = finalhandler(req, res)
270 + logger(req, res, function (err) {
271 + if (err) return done(err)
272 +
273 + // respond to request
274 + res.setHeader('content-type', 'text/plain')
275 + res.end('hello, world!')
276 + })
277 +})
278 +```
279 +
280 +### write logs to a file
281 +
282 +#### single file
283 +
284 +Simple app that will log all requests in the Apache combined format to the file
285 +`access.log`.
286 +
287 +```js
288 +var express = require('express')
289 +var fs = require('fs')
290 +var morgan = require('morgan')
291 +var path = require('path')
292 +
293 +var app = express()
294 +
295 +// create a write stream (in append mode)
296 +var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'})
297 +
298 +// setup the logger
299 +app.use(morgan('combined', {stream: accessLogStream}))
300 +
301 +app.get('/', function (req, res) {
302 + res.send('hello, world!')
303 +})
304 +```
305 +
306 +#### log file rotation
307 +
308 +Simple app that will log all requests in the Apache combined format to one log
309 +file per day in the `log/` directory using the
310 +[rotating-file-stream module](https://www.npmjs.com/package/rotating-file-stream).
311 +
312 +```js
313 +var express = require('express')
314 +var fs = require('fs')
315 +var morgan = require('morgan')
316 +var path = require('path')
317 +var rfs = require('rotating-file-stream')
318 +
319 +var app = express()
320 +var logDirectory = path.join(__dirname, 'log')
321 +
322 +// ensure log directory exists
323 +fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory)
324 +
325 +// create a rotating write stream
326 +var accessLogStream = rfs('access.log', {
327 + interval: '1d', // rotate daily
328 + path: logDirectory
329 +})
330 +
331 +// setup the logger
332 +app.use(morgan('combined', {stream: accessLogStream}))
333 +
334 +app.get('/', function (req, res) {
335 + res.send('hello, world!')
336 +})
337 +```
338 +
339 +### split / dual logging
340 +
341 +The `morgan` middleware can be used as many times as needed, enabling
342 +combinations like:
343 +
344 + * Log entry on request and one on response
345 + * Log all requests to file, but errors to console
346 + * ... and more!
347 +
348 +Sample app that will log all requests to a file using Apache format, but
349 +error responses are logged to the console:
350 +
351 +```js
352 +var express = require('express')
353 +var fs = require('fs')
354 +var morgan = require('morgan')
355 +var path = require('path')
356 +
357 +var app = express()
358 +
359 +// log only 4xx and 5xx responses to console
360 +app.use(morgan('dev', {
361 + skip: function (req, res) { return res.statusCode < 400 }
362 +}))
363 +
364 +// log all requests to access.log
365 +app.use(morgan('common', {
366 + stream: fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'})
367 +}))
368 +
369 +app.get('/', function (req, res) {
370 + res.send('hello, world!')
371 +})
372 +```
373 +
374 +### use custom token formats
375 +
376 +Sample app that will use custom token formats. This adds an ID to all requests and displays it using the `:id` token.
377 +
378 +```js
379 +var express = require('express')
380 +var morgan = require('morgan')
381 +var uuid = require('node-uuid')
382 +
383 +morgan.token('id', function getId (req) {
384 + return req.id
385 +})
386 +
387 +var app = express()
388 +
389 +app.use(assignId)
390 +app.use(morgan(':id :method :url :response-time'))
391 +
392 +app.get('/', function (req, res) {
393 + res.send('hello, world!')
394 +})
395 +
396 +function assignId (req, res, next) {
397 + req.id = uuid.v4()
398 + next()
399 +}
400 +```
401 +
402 +## License
403 +
404 +[MIT](LICENSE)
405 +
406 +[npm-image]: https://img.shields.io/npm/v/morgan.svg
407 +[npm-url]: https://npmjs.org/package/morgan
408 +[travis-image]: https://img.shields.io/travis/expressjs/morgan/master.svg
409 +[travis-url]: https://travis-ci.org/expressjs/morgan
410 +[coveralls-image]: https://img.shields.io/coveralls/expressjs/morgan/master.svg
411 +[coveralls-url]: https://coveralls.io/r/expressjs/morgan?branch=master
412 +[downloads-image]: https://img.shields.io/npm/dm/morgan.svg
413 +[downloads-url]: https://npmjs.org/package/morgan
414 +[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
415 +[gratipay-url]: https://www.gratipay.com/dougwilson/
1 +/*!
2 + * morgan
3 + * Copyright(c) 2010 Sencha Inc.
4 + * Copyright(c) 2011 TJ Holowaychuk
5 + * Copyright(c) 2014 Jonathan Ong
6 + * Copyright(c) 2014-2017 Douglas Christopher Wilson
7 + * MIT Licensed
8 + */
9 +
10 +'use strict'
11 +
12 +/**
13 + * Module exports.
14 + * @public
15 + */
16 +
17 +module.exports = morgan
18 +module.exports.compile = compile
19 +module.exports.format = format
20 +module.exports.token = token
21 +
22 +/**
23 + * Module dependencies.
24 + * @private
25 + */
26 +
27 +var auth = require('basic-auth')
28 +var debug = require('debug')('morgan')
29 +var deprecate = require('depd')('morgan')
30 +var onFinished = require('on-finished')
31 +var onHeaders = require('on-headers')
32 +
33 +/**
34 + * Array of CLF month names.
35 + * @private
36 + */
37 +
38 +var CLF_MONTH = [
39 + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
40 + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
41 +]
42 +
43 +/**
44 + * Default log buffer duration.
45 + * @private
46 + */
47 +
48 +var DEFAULT_BUFFER_DURATION = 1000
49 +
50 +/**
51 + * Create a logger middleware.
52 + *
53 + * @public
54 + * @param {String|Function} format
55 + * @param {Object} [options]
56 + * @return {Function} middleware
57 + */
58 +
59 +function morgan (format, options) {
60 + var fmt = format
61 + var opts = options || {}
62 +
63 + if (format && typeof format === 'object') {
64 + opts = format
65 + fmt = opts.format || 'default'
66 +
67 + // smart deprecation message
68 + deprecate('morgan(options): use morgan(' + (typeof fmt === 'string' ? JSON.stringify(fmt) : 'format') + ', options) instead')
69 + }
70 +
71 + if (fmt === undefined) {
72 + deprecate('undefined format: specify a format')
73 + }
74 +
75 + // output on request instead of response
76 + var immediate = opts.immediate
77 +
78 + // check if log entry should be skipped
79 + var skip = opts.skip || false
80 +
81 + // format function
82 + var formatLine = typeof fmt !== 'function'
83 + ? getFormatFunction(fmt)
84 + : fmt
85 +
86 + // stream
87 + var buffer = opts.buffer
88 + var stream = opts.stream || process.stdout
89 +
90 + // buffering support
91 + if (buffer) {
92 + deprecate('buffer option')
93 +
94 + // flush interval
95 + var interval = typeof buffer !== 'number'
96 + ? DEFAULT_BUFFER_DURATION
97 + : buffer
98 +
99 + // swap the stream
100 + stream = createBufferStream(stream, interval)
101 + }
102 +
103 + return function logger (req, res, next) {
104 + // request data
105 + req._startAt = undefined
106 + req._startTime = undefined
107 + req._remoteAddress = getip(req)
108 +
109 + // response data
110 + res._startAt = undefined
111 + res._startTime = undefined
112 +
113 + // record request start
114 + recordStartTime.call(req)
115 +
116 + function logRequest () {
117 + if (skip !== false && skip(req, res)) {
118 + debug('skip request')
119 + return
120 + }
121 +
122 + var line = formatLine(morgan, req, res)
123 +
124 + if (line == null) {
125 + debug('skip line')
126 + return
127 + }
128 +
129 + debug('log request')
130 + stream.write(line + '\n')
131 + };
132 +
133 + if (immediate) {
134 + // immediate log
135 + logRequest()
136 + } else {
137 + // record response start
138 + onHeaders(res, recordStartTime)
139 +
140 + // log when response finished
141 + onFinished(res, logRequest)
142 + }
143 +
144 + next()
145 + }
146 +}
147 +
148 +/**
149 + * Apache combined log format.
150 + */
151 +
152 +morgan.format('combined', ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"')
153 +
154 +/**
155 + * Apache common log format.
156 + */
157 +
158 +morgan.format('common', ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]')
159 +
160 +/**
161 + * Default format.
162 + */
163 +
164 +morgan.format('default', ':remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"')
165 +deprecate.property(morgan, 'default', 'default format: use combined format')
166 +
167 +/**
168 + * Short format.
169 + */
170 +
171 +morgan.format('short', ':remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms')
172 +
173 +/**
174 + * Tiny format.
175 + */
176 +
177 +morgan.format('tiny', ':method :url :status :res[content-length] - :response-time ms')
178 +
179 +/**
180 + * dev (colored)
181 + */
182 +
183 +morgan.format('dev', function developmentFormatLine (tokens, req, res) {
184 + // get the status code if response written
185 + var status = headersSent(res)
186 + ? res.statusCode
187 + : undefined
188 +
189 + // get status color
190 + var color = status >= 500 ? 31 // red
191 + : status >= 400 ? 33 // yellow
192 + : status >= 300 ? 36 // cyan
193 + : status >= 200 ? 32 // green
194 + : 0 // no color
195 +
196 + // get colored function
197 + var fn = developmentFormatLine[color]
198 +
199 + if (!fn) {
200 + // compile
201 + fn = developmentFormatLine[color] = compile('\x1b[0m:method :url \x1b[' +
202 + color + 'm:status \x1b[0m:response-time ms - :res[content-length]\x1b[0m')
203 + }
204 +
205 + return fn(tokens, req, res)
206 +})
207 +
208 +/**
209 + * request url
210 + */
211 +
212 +morgan.token('url', function getUrlToken (req) {
213 + return req.originalUrl || req.url
214 +})
215 +
216 +/**
217 + * request method
218 + */
219 +
220 +morgan.token('method', function getMethodToken (req) {
221 + return req.method
222 +})
223 +
224 +/**
225 + * response time in milliseconds
226 + */
227 +
228 +morgan.token('response-time', function getResponseTimeToken (req, res, digits) {
229 + if (!req._startAt || !res._startAt) {
230 + // missing request and/or response start time
231 + return
232 + }
233 +
234 + // calculate diff
235 + var ms = (res._startAt[0] - req._startAt[0]) * 1e3 +
236 + (res._startAt[1] - req._startAt[1]) * 1e-6
237 +
238 + // return truncated value
239 + return ms.toFixed(digits === undefined ? 3 : digits)
240 +})
241 +
242 +/**
243 + * current date
244 + */
245 +
246 +morgan.token('date', function getDateToken (req, res, format) {
247 + var date = new Date()
248 +
249 + switch (format || 'web') {
250 + case 'clf':
251 + return clfdate(date)
252 + case 'iso':
253 + return date.toISOString()
254 + case 'web':
255 + return date.toUTCString()
256 + }
257 +})
258 +
259 +/**
260 + * response status code
261 + */
262 +
263 +morgan.token('status', function getStatusToken (req, res) {
264 + return headersSent(res)
265 + ? String(res.statusCode)
266 + : undefined
267 +})
268 +
269 +/**
270 + * normalized referrer
271 + */
272 +
273 +morgan.token('referrer', function getReferrerToken (req) {
274 + return req.headers['referer'] || req.headers['referrer']
275 +})
276 +
277 +/**
278 + * remote address
279 + */
280 +
281 +morgan.token('remote-addr', getip)
282 +
283 +/**
284 + * remote user
285 + */
286 +
287 +morgan.token('remote-user', function getRemoteUserToken (req) {
288 + // parse basic credentials
289 + var credentials = auth(req)
290 +
291 + // return username
292 + return credentials
293 + ? credentials.name
294 + : undefined
295 +})
296 +
297 +/**
298 + * HTTP version
299 + */
300 +
301 +morgan.token('http-version', function getHttpVersionToken (req) {
302 + return req.httpVersionMajor + '.' + req.httpVersionMinor
303 +})
304 +
305 +/**
306 + * UA string
307 + */
308 +
309 +morgan.token('user-agent', function getUserAgentToken (req) {
310 + return req.headers['user-agent']
311 +})
312 +
313 +/**
314 + * request header
315 + */
316 +
317 +morgan.token('req', function getRequestToken (req, res, field) {
318 + // get header
319 + var header = req.headers[field.toLowerCase()]
320 +
321 + return Array.isArray(header)
322 + ? header.join(', ')
323 + : header
324 +})
325 +
326 +/**
327 + * response header
328 + */
329 +
330 +morgan.token('res', function getResponseHeader (req, res, field) {
331 + if (!headersSent(res)) {
332 + return undefined
333 + }
334 +
335 + // get header
336 + var header = res.getHeader(field)
337 +
338 + return Array.isArray(header)
339 + ? header.join(', ')
340 + : header
341 +})
342 +
343 +/**
344 + * Format a Date in the common log format.
345 + *
346 + * @private
347 + * @param {Date} dateTime
348 + * @return {string}
349 + */
350 +
351 +function clfdate (dateTime) {
352 + var date = dateTime.getUTCDate()
353 + var hour = dateTime.getUTCHours()
354 + var mins = dateTime.getUTCMinutes()
355 + var secs = dateTime.getUTCSeconds()
356 + var year = dateTime.getUTCFullYear()
357 +
358 + var month = CLF_MONTH[dateTime.getUTCMonth()]
359 +
360 + return pad2(date) + '/' + month + '/' + year +
361 + ':' + pad2(hour) + ':' + pad2(mins) + ':' + pad2(secs) +
362 + ' +0000'
363 +}
364 +
365 +/**
366 + * Compile a format string into a function.
367 + *
368 + * @param {string} format
369 + * @return {function}
370 + * @public
371 + */
372 +
373 +function compile (format) {
374 + if (typeof format !== 'string') {
375 + throw new TypeError('argument format must be a string')
376 + }
377 +
378 + var fmt = format.replace(/"/g, '\\"')
379 + var js = ' "use strict"\n return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function (_, name, arg) {
380 + var tokenArguments = 'req, res'
381 + var tokenFunction = 'tokens[' + String(JSON.stringify(name)) + ']'
382 +
383 + if (arg !== undefined) {
384 + tokenArguments += ', ' + String(JSON.stringify(arg))
385 + }
386 +
387 + return '" +\n (' + tokenFunction + '(' + tokenArguments + ') || "-") + "'
388 + }) + '"'
389 +
390 + // eslint-disable-next-line no-new-func
391 + return new Function('tokens, req, res', js)
392 +}
393 +
394 +/**
395 + * Create a basic buffering stream.
396 + *
397 + * @param {object} stream
398 + * @param {number} interval
399 + * @public
400 + */
401 +
402 +function createBufferStream (stream, interval) {
403 + var buf = []
404 + var timer = null
405 +
406 + // flush function
407 + function flush () {
408 + timer = null
409 + stream.write(buf.join(''))
410 + buf.length = 0
411 + }
412 +
413 + // write function
414 + function write (str) {
415 + if (timer === null) {
416 + timer = setTimeout(flush, interval)
417 + }
418 +
419 + buf.push(str)
420 + }
421 +
422 + // return a minimal "stream"
423 + return { write: write }
424 +}
425 +
426 +/**
427 + * Define a format with the given name.
428 + *
429 + * @param {string} name
430 + * @param {string|function} fmt
431 + * @public
432 + */
433 +
434 +function format (name, fmt) {
435 + morgan[name] = fmt
436 + return this
437 +}
438 +
439 +/**
440 + * Lookup and compile a named format function.
441 + *
442 + * @param {string} name
443 + * @return {function}
444 + * @public
445 + */
446 +
447 +function getFormatFunction (name) {
448 + // lookup format
449 + var fmt = morgan[name] || name || morgan.default
450 +
451 + // return compiled format
452 + return typeof fmt !== 'function'
453 + ? compile(fmt)
454 + : fmt
455 +}
456 +
457 +/**
458 + * Get request IP address.
459 + *
460 + * @private
461 + * @param {IncomingMessage} req
462 + * @return {string}
463 + */
464 +
465 +function getip (req) {
466 + return req.ip ||
467 + req._remoteAddress ||
468 + (req.connection && req.connection.remoteAddress) ||
469 + undefined
470 +}
471 +
472 +/**
473 + * Determine if the response headers have been sent.
474 + *
475 + * @param {object} res
476 + * @returns {boolean}
477 + * @private
478 + */
479 +
480 +function headersSent (res) {
481 + return typeof res.headersSent !== 'boolean'
482 + ? Boolean(res._header)
483 + : res.headersSent
484 +}
485 +
486 +/**
487 + * Pad number to two digits.
488 + *
489 + * @private
490 + * @param {number} num
491 + * @return {string}
492 + */
493 +
494 +function pad2 (num) {
495 + var str = String(num)
496 +
497 + return (str.length === 1 ? '0' : '') + str
498 +}
499 +
500 +/**
501 + * Record the start time.
502 + * @private
503 + */
504 +
505 +function recordStartTime () {
506 + this._startAt = process.hrtime()
507 + this._startTime = new Date()
508 +}
509 +
510 +/**
511 + * Define a token function with the given name,
512 + * and callback fn(req, res).
513 + *
514 + * @param {string} name
515 + * @param {function} fn
516 + * @public
517 + */
518 +
519 +function token (name, fn) {
520 + morgan[name] = fn
521 + return this
522 +}
1 +{
2 + "_from": "morgan@~1.9.0",
3 + "_id": "morgan@1.9.0",
4 + "_inBundle": false,
5 + "_integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=",
6 + "_location": "/morgan",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "morgan@~1.9.0",
12 + "name": "morgan",
13 + "escapedName": "morgan",
14 + "rawSpec": "~1.9.0",
15 + "saveSpec": null,
16 + "fetchSpec": "~1.9.0"
17 + },
18 + "_requiredBy": [
19 + "/"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
22 + "_shasum": "d01fa6c65859b76fcf31b3cb53a3821a311d8051",
23 + "_spec": "morgan@~1.9.0",
24 + "_where": "/home/ubuntu/OpenSource_Project",
25 + "bugs": {
26 + "url": "https://github.com/expressjs/morgan/issues"
27 + },
28 + "bundleDependencies": false,
29 + "contributors": [
30 + {
31 + "name": "Douglas Christopher Wilson",
32 + "email": "doug@somethingdoug.com"
33 + },
34 + {
35 + "name": "Jonathan Ong",
36 + "email": "me@jongleberry.com",
37 + "url": "http://jongleberry.com"
38 + }
39 + ],
40 + "dependencies": {
41 + "basic-auth": "~2.0.0",
42 + "debug": "2.6.9",
43 + "depd": "~1.1.1",
44 + "on-finished": "~2.3.0",
45 + "on-headers": "~1.0.1"
46 + },
47 + "deprecated": false,
48 + "description": "HTTP request logger middleware for node.js",
49 + "devDependencies": {
50 + "eslint": "3.19.0",
51 + "eslint-config-standard": "10.2.1",
52 + "eslint-plugin-import": "2.7.0",
53 + "eslint-plugin-markdown": "1.0.0-beta.6",
54 + "eslint-plugin-node": "5.1.1",
55 + "eslint-plugin-promise": "3.5.0",
56 + "eslint-plugin-standard": "3.0.1",
57 + "istanbul": "0.4.5",
58 + "mocha": "2.5.3",
59 + "split": "1.0.1",
60 + "supertest": "1.1.0"
61 + },
62 + "engines": {
63 + "node": ">= 0.8.0"
64 + },
65 + "files": [
66 + "LICENSE",
67 + "HISTORY.md",
68 + "README.md",
69 + "index.js"
70 + ],
71 + "homepage": "https://github.com/expressjs/morgan#readme",
72 + "keywords": [
73 + "express",
74 + "http",
75 + "logger",
76 + "middleware"
77 + ],
78 + "license": "MIT",
79 + "name": "morgan",
80 + "repository": {
81 + "type": "git",
82 + "url": "git+https://github.com/expressjs/morgan.git"
83 + },
84 + "scripts": {
85 + "lint": "eslint --plugin markdown --ext js,md .",
86 + "test": "mocha --check-leaks --reporter spec --bail",
87 + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --reporter dot",
88 + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --reporter spec"
89 + },
90 + "version": "1.9.0"
91 +}
1 +1.0.1 / 2015-09-29
2 +==================
3 +
4 + * perf: enable strict mode
5 +
6 +1.0.0 / 2014-08-10
7 +==================
8 +
9 + * Honor `res.statusCode` change in `listener`
10 + * Move to `jshttp` orgainzation
11 + * Prevent `arguments`-related de-opt
12 +
13 +0.0.0 / 2014-05-13
14 +==================
15 +
16 + * Initial implementation
1 +(The MIT License)
2 +
3 +Copyright (c) 2014 Douglas Christopher Wilson
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining
6 +a copy of this software and associated documentation files (the
7 +'Software'), to deal in the Software without restriction, including
8 +without limitation the rights to use, copy, modify, merge, publish,
9 +distribute, sublicense, and/or sell copies of the Software, and to
10 +permit persons to whom the Software is furnished to do so, subject to
11 +the following conditions:
12 +
13 +The above copyright notice and this permission notice shall be
14 +included in all copies or substantial portions of the Software.
15 +
16 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +# on-headers
2 +
3 +[![NPM Version][npm-image]][npm-url]
4 +[![NPM Downloads][downloads-image]][downloads-url]
5 +[![Node.js Version][node-version-image]][node-version-url]
6 +[![Build Status][travis-image]][travis-url]
7 +[![Test Coverage][coveralls-image]][coveralls-url]
8 +
9 +Execute a listener when a response is about to write headers.
10 +
11 +## Installation
12 +
13 +```sh
14 +$ npm install on-headers
15 +```
16 +
17 +## API
18 +
19 +```js
20 +var onHeaders = require('on-headers')
21 +```
22 +
23 +### onHeaders(res, listener)
24 +
25 +This will add the listener `listener` to fire when headers are emitted for `res`.
26 +The listener is passed the `response` object as it's context (`this`). Headers are
27 +considered to be emitted only once, right before they are sent to the client.
28 +
29 +When this is called multiple times on the same `res`, the `listener`s are fired
30 +in the reverse order they were added.
31 +
32 +## Examples
33 +
34 +```js
35 +var http = require('http')
36 +var onHeaders = require('on-headers')
37 +
38 +http
39 +.createServer(onRequest)
40 +.listen(3000)
41 +
42 +function addPoweredBy() {
43 + // set if not set by end of request
44 + if (!this.getHeader('X-Powered-By')) {
45 + this.setHeader('X-Powered-By', 'Node.js')
46 + }
47 +}
48 +
49 +function onRequest(req, res) {
50 + onHeaders(res, addPoweredBy)
51 +
52 + res.setHeader('Content-Type', 'text/plain')
53 + res.end('hello!')
54 +}
55 +```
56 +
57 +## Testing
58 +
59 +```sh
60 +$ npm test
61 +```
62 +
63 +## License
64 +
65 +[MIT](LICENSE)
66 +
67 +[npm-image]: https://img.shields.io/npm/v/on-headers.svg
68 +[npm-url]: https://npmjs.org/package/on-headers
69 +[node-version-image]: https://img.shields.io/node/v/on-headers.svg
70 +[node-version-url]: http://nodejs.org/download/
71 +[travis-image]: https://img.shields.io/travis/jshttp/on-headers/master.svg
72 +[travis-url]: https://travis-ci.org/jshttp/on-headers
73 +[coveralls-image]: https://img.shields.io/coveralls/jshttp/on-headers/master.svg
74 +[coveralls-url]: https://coveralls.io/r/jshttp/on-headers?branch=master
75 +[downloads-image]: https://img.shields.io/npm/dm/on-headers.svg
76 +[downloads-url]: https://npmjs.org/package/on-headers
1 +/*!
2 + * on-headers
3 + * Copyright(c) 2014 Douglas Christopher Wilson
4 + * MIT Licensed
5 + */
6 +
7 +'use strict'
8 +
9 +/**
10 + * Reference to Array slice.
11 + */
12 +
13 +var slice = Array.prototype.slice
14 +
15 +/**
16 + * Execute a listener when a response is about to write headers.
17 + *
18 + * @param {Object} res
19 + * @return {Function} listener
20 + * @api public
21 + */
22 +
23 +module.exports = function onHeaders(res, listener) {
24 + if (!res) {
25 + throw new TypeError('argument res is required')
26 + }
27 +
28 + if (typeof listener !== 'function') {
29 + throw new TypeError('argument listener must be a function')
30 + }
31 +
32 + res.writeHead = createWriteHead(res.writeHead, listener)
33 +}
34 +
35 +function createWriteHead(prevWriteHead, listener) {
36 + var fired = false;
37 +
38 + // return function with core name and argument list
39 + return function writeHead(statusCode) {
40 + // set headers from arguments
41 + var args = setWriteHeadHeaders.apply(this, arguments);
42 +
43 + // fire listener
44 + if (!fired) {
45 + fired = true
46 + listener.call(this)
47 +
48 + // pass-along an updated status code
49 + if (typeof args[0] === 'number' && this.statusCode !== args[0]) {
50 + args[0] = this.statusCode
51 + args.length = 1
52 + }
53 + }
54 +
55 + prevWriteHead.apply(this, args);
56 + }
57 +}
58 +
59 +function setWriteHeadHeaders(statusCode) {
60 + var length = arguments.length
61 + var headerIndex = length > 1 && typeof arguments[1] === 'string'
62 + ? 2
63 + : 1
64 +
65 + var headers = length >= headerIndex + 1
66 + ? arguments[headerIndex]
67 + : undefined
68 +
69 + this.statusCode = statusCode
70 +
71 + // the following block is from node.js core
72 + if (Array.isArray(headers)) {
73 + // handle array case
74 + for (var i = 0, len = headers.length; i < len; ++i) {
75 + this.setHeader(headers[i][0], headers[i][1])
76 + }
77 + } else if (headers) {
78 + // handle object case
79 + var keys = Object.keys(headers)
80 + for (var i = 0; i < keys.length; i++) {
81 + var k = keys[i]
82 + if (k) this.setHeader(k, headers[k])
83 + }
84 + }
85 +
86 + // copy leading arguments
87 + var args = new Array(Math.min(length, headerIndex))
88 + for (var i = 0; i < args.length; i++) {
89 + args[i] = arguments[i]
90 + }
91 +
92 + return args
93 +}
1 +{
2 + "_from": "on-headers@~1.0.1",
3 + "_id": "on-headers@1.0.1",
4 + "_inBundle": false,
5 + "_integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=",
6 + "_location": "/on-headers",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "on-headers@~1.0.1",
12 + "name": "on-headers",
13 + "escapedName": "on-headers",
14 + "rawSpec": "~1.0.1",
15 + "saveSpec": null,
16 + "fetchSpec": "~1.0.1"
17 + },
18 + "_requiredBy": [
19 + "/morgan"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
22 + "_shasum": "928f5d0f470d49342651ea6794b0857c100693f7",
23 + "_spec": "on-headers@~1.0.1",
24 + "_where": "/home/ubuntu/OpenSource_Project/node_modules/morgan",
25 + "author": {
26 + "name": "Douglas Christopher Wilson",
27 + "email": "doug@somethingdoug.com"
28 + },
29 + "bugs": {
30 + "url": "https://github.com/jshttp/on-headers/issues"
31 + },
32 + "bundleDependencies": false,
33 + "dependencies": {},
34 + "deprecated": false,
35 + "description": "Execute a listener when a response is about to write headers",
36 + "devDependencies": {
37 + "istanbul": "0.3.21",
38 + "mocha": "2.3.3",
39 + "supertest": "1.1.0"
40 + },
41 + "engines": {
42 + "node": ">= 0.8"
43 + },
44 + "files": [
45 + "LICENSE",
46 + "HISTORY.md",
47 + "README.md",
48 + "index.js"
49 + ],
50 + "homepage": "https://github.com/jshttp/on-headers#readme",
51 + "keywords": [
52 + "event",
53 + "headers",
54 + "http",
55 + "onheaders"
56 + ],
57 + "license": "MIT",
58 + "name": "on-headers",
59 + "repository": {
60 + "type": "git",
61 + "url": "git+https://github.com/jshttp/on-headers.git"
62 + },
63 + "scripts": {
64 + "test": "mocha --reporter spec --bail --check-leaks test/",
65 + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
66 + "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
67 + },
68 + "version": "1.0.1"
69 +}
1 +2.4.5 / 2017-09-26
2 +==================
3 +
4 + * deps: etag@~1.8.1
5 + - perf: replace regular expression with substring
6 + * deps: fresh@0.5.2
7 + - Fix regression matching multiple ETags in `If-None-Match`
8 + - perf: improve `If-None-Match` token parsing
9 +
10 +2.4.4 / 2017-09-11
11 +==================
12 +
13 + * deps: fresh@0.5.1
14 + - Fix handling of modified headers with invalid dates
15 + - perf: improve ETag match loop
16 + * deps: parseurl@~1.3.2
17 + - perf: reduce overhead for full URLs
18 + - perf: unroll the "fast-path" `RegExp`
19 + * deps: safe-buffer@5.1.1
20 +
21 +2.4.3 / 2017-05-16
22 +==================
23 +
24 + * Use `safe-buffer` for improved Buffer API
25 + * deps: ms@2.0.0
26 +
27 +2.4.2 / 2017-03-24
28 +==================
29 +
30 + * deps: ms@1.0.0
31 +
32 +2.4.1 / 2017-02-27
33 +==================
34 +
35 + * Remove usage of `res._headers` private field
36 + * deps: fresh@0.5.0
37 + - Fix incorrect result when `If-None-Match` has both `*` and ETags
38 + - Fix weak `ETag` matching to match spec
39 + - perf: skip checking modified time if ETag check failed
40 + - perf: skip parsing `If-None-Match` when no `ETag` header
41 + - perf: use `Date.parse` instead of `new Date`
42 +
43 +2.4.0 / 2017-02-19
44 +==================
45 +
46 + * deps: etag@~1.8.0
47 + - Use SHA1 instead of MD5 for ETag hashing
48 + - Works with FIPS 140-2 OpenSSL configuration
49 + * deps: fresh@0.4.0
50 + - Fix false detection of `no-cache` request directive
51 + - perf: enable strict mode
52 + - perf: hoist regular expressions
53 + - perf: remove duplicate conditional
54 + - perf: remove unnecessary boolean coercions
55 + * perf: simplify initial argument checking
56 +
57 +2.3.2 / 2016-11-16
58 +==================
59 +
60 + * deps: ms@0.7.2
61 +
62 +2.3.1 / 2016-01-23
63 +==================
64 +
65 + * deps: parseurl@~1.3.1
66 + - perf: enable strict mode
67 +
68 +2.3.0 / 2015-06-13
69 +==================
70 +
71 + * Send non-chunked response for `OPTIONS`
72 + * deps: etag@~1.7.0
73 + - Always include entity length in ETags for hash length extensions
74 + - Generate non-Stats ETags using MD5 only (no longer CRC32)
75 + - Remove base64 padding in ETags to shorten
76 + * deps: fresh@0.3.0
77 + - Add weak `ETag` matching support
78 + * perf: enable strict mode
79 + * perf: remove argument reassignment
80 + * perf: remove bitwise operations
81 +
82 +2.2.1 / 2015-05-14
83 +==================
84 +
85 + * deps: etag@~1.6.0
86 + - Improve support for JXcore
87 + - Support "fake" stats objects in environments without `fs`
88 + * deps: ms@0.7.1
89 + - Prevent extraordinarily long inputs
90 +
91 +2.2.0 / 2014-12-18
92 +==================
93 +
94 + * Support query string in the URL
95 + * deps: etag@~1.5.1
96 + - deps: crc@3.2.1
97 + * deps: ms@0.7.0
98 + - Add `milliseconds`
99 + - Add `msecs`
100 + - Add `secs`
101 + - Add `mins`
102 + - Add `hrs`
103 + - Add `yrs`
104 +
105 +2.1.7 / 2014-11-19
106 +==================
107 +
108 + * Avoid errors from enumerables on `Object.prototype`
109 +
110 +2.1.6 / 2014-10-16
111 +==================
112 +
113 + * deps: etag@~1.5.0
114 +
115 +2.1.5 / 2014-09-24
116 +==================
117 +
118 + * deps: etag@~1.4.0
119 +
120 +2.1.4 / 2014-09-15
121 +==================
122 +
123 + * Fix content headers being sent in 304 response
124 + * deps: etag@~1.3.1
125 + - Improve ETag generation speed
126 +
127 +2.1.3 / 2014-09-07
128 +==================
129 +
130 + * deps: fresh@0.2.4
131 +
132 +2.1.2 / 2014-09-05
133 +==================
134 +
135 + * deps: etag@~1.3.0
136 + - Improve ETag generation speed
137 +
138 +2.1.1 / 2014-08-25
139 +==================
140 +
141 + * Fix `ms` to be listed as a dependency
142 +
143 +2.1.0 / 2014-08-24
144 +==================
145 +
146 + * Accept string for `maxAge` (converted by `ms`)
147 + * Use `etag` to generate `ETag` header
148 +
149 +2.0.1 / 2014-06-05
150 +==================
151 +
152 + * Reduce byte size of `ETag` header
153 +
154 +2.0.0 / 2014-05-02
155 +==================
156 +
157 + * `path` argument is required; there is no default icon.
158 + * Accept `Buffer` of icon as first argument.
159 + * Non-GET and HEAD requests are denied.
160 + * Send valid max-age value
161 + * Support conditional requests
162 + * Support max-age=0
163 + * Support OPTIONS method
164 + * Throw if `path` argument is directory.
165 +
166 +1.0.2 / 2014-03-16
167 +==================
168 +
169 + * Fixed content of default icon.
170 +
171 +1.0.1 / 2014-03-11
172 +==================
173 +
174 + * Fixed path to default icon.
175 +
176 +1.0.0 / 2014-02-15
177 +==================
178 +
179 + * Initial release
1 +(The MIT License)
2 +
3 +Copyright (c) 2010 Sencha Inc.
4 +Copyright (c) 2011 LearnBoost
5 +Copyright (c) 2011 TJ Holowaychuk
6 +Copyright (c) 2014-2017 Douglas Christopher Wilson
7 +
8 +Permission is hereby granted, free of charge, to any person obtaining
9 +a copy of this software and associated documentation files (the
10 +'Software'), to deal in the Software without restriction, including
11 +without limitation the rights to use, copy, modify, merge, publish,
12 +distribute, sublicense, and/or sell copies of the Software, and to
13 +permit persons to whom the Software is furnished to do so, subject to
14 +the following conditions:
15 +
16 +The above copyright notice and this permission notice shall be
17 +included in all copies or substantial portions of the Software.
18 +
19 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
20 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +# serve-favicon
2 +
3 +[![NPM Version][npm-image]][npm-url]
4 +[![NPM Downloads][downloads-image]][downloads-url]
5 +[![Linux Build][travis-image]][travis-url]
6 +[![Windows Build][appveyor-image]][appveyor-url]
7 +[![Test Coverage][coveralls-image]][coveralls-url]
8 +[![Gratipay][gratipay-image]][gratipay-url]
9 +
10 +Node.js middleware for serving a favicon.
11 +
12 +A favicon is a visual cue that client software, like browsers, use to identify
13 +a site. For an example and more information, please visit
14 +[the Wikipedia article on favicons](https://en.wikipedia.org/wiki/Favicon).
15 +
16 +Why use this module?
17 +
18 + - User agents request `favicon.ico` frequently and indiscriminately, so you
19 + may wish to exclude these requests from your logs by using this middleware
20 + before your logger middleware.
21 + - This module caches the icon in memory to improve performance by skipping
22 + disk access.
23 + - This module provides an `ETag` based on the contents of the icon, rather
24 + than file system properties.
25 + - This module will serve with the most compatible `Content-Type`.
26 +
27 +**Note** This module is exclusively for serving the "default, implicit favicon",
28 +which is `GET /favicon.ico`. For additional vendor-specific icons that require
29 +HTML markup, additional middleware is required to serve the relevant files, for
30 +example [serve-static](https://npmjs.org/package/serve-static).
31 +
32 +## Install
33 +
34 +This is a [Node.js](https://nodejs.org/en/) module available through the
35 +[npm registry](https://www.npmjs.com/). Installation is done using the
36 +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
37 +
38 +```sh
39 +$ npm install serve-favicon
40 +```
41 +
42 +## API
43 +
44 +### favicon(path, options)
45 +
46 +Create new middleware to serve a favicon from the given `path` to a favicon file.
47 +`path` may also be a `Buffer` of the icon to serve.
48 +
49 +#### Options
50 +
51 +Serve favicon accepts these properties in the options object.
52 +
53 +##### maxAge
54 +
55 +The `cache-control` `max-age` directive in `ms`, defaulting to 1 year. This can
56 +also be a string accepted by the [ms](https://www.npmjs.org/package/ms#readme)
57 +module.
58 +
59 +## Examples
60 +
61 +Typically this middleware will come very early in your stack (maybe even first)
62 +to avoid processing any other middleware if we already know the request is for
63 +`/favicon.ico`.
64 +
65 +### express
66 +
67 +```javascript
68 +var express = require('express')
69 +var favicon = require('serve-favicon')
70 +var path = require('path')
71 +
72 +var app = express()
73 +app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
74 +
75 +// Add your routes here, etc.
76 +
77 +app.listen(3000)
78 +```
79 +
80 +### connect
81 +
82 +```javascript
83 +var connect = require('connect')
84 +var favicon = require('serve-favicon')
85 +var path = require('path')
86 +
87 +var app = connect()
88 +app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
89 +
90 +// Add your middleware here, etc.
91 +
92 +app.listen(3000)
93 +```
94 +
95 +### vanilla http server
96 +
97 +This middleware can be used anywhere, even outside express/connect. It takes
98 +`req`, `res`, and `callback`.
99 +
100 +```javascript
101 +var http = require('http')
102 +var favicon = require('serve-favicon')
103 +var finalhandler = require('finalhandler')
104 +var path = require('path')
105 +
106 +var _favicon = favicon(path.join(__dirname, 'public', 'favicon.ico'))
107 +
108 +var server = http.createServer(function onRequest (req, res) {
109 + var done = finalhandler(req, res)
110 +
111 + _favicon(req, res, function onNext (err) {
112 + if (err) return done(err)
113 +
114 + // continue to process the request here, etc.
115 +
116 + res.statusCode = 404
117 + res.end('oops')
118 + })
119 +})
120 +
121 +server.listen(3000)
122 +```
123 +
124 +## License
125 +
126 +[MIT](LICENSE)
127 +
128 +[npm-image]: https://img.shields.io/npm/v/serve-favicon.svg
129 +[npm-url]: https://npmjs.org/package/serve-favicon
130 +[travis-image]: https://img.shields.io/travis/expressjs/serve-favicon/master.svg?label=linux
131 +[travis-url]: https://travis-ci.org/expressjs/serve-favicon
132 +[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/serve-favicon/master.svg?label=windows
133 +[appveyor-url]: https://ci.appveyor.com/project/dougwilson/serve-favicon
134 +[coveralls-image]: https://img.shields.io/coveralls/expressjs/serve-favicon.svg
135 +[coveralls-url]: https://coveralls.io/r/expressjs/serve-favicon?branch=master
136 +[downloads-image]: https://img.shields.io/npm/dm/serve-favicon.svg
137 +[downloads-url]: https://npmjs.org/package/serve-favicon
138 +[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
139 +[gratipay-url]: https://www.gratipay.com/dougwilson/
1 +/*!
2 + * serve-favicon
3 + * Copyright(c) 2010 Sencha Inc.
4 + * Copyright(c) 2011 TJ Holowaychuk
5 + * Copyright(c) 2014-2017 Douglas Christopher Wilson
6 + * MIT Licensed
7 + */
8 +
9 +'use strict'
10 +
11 +/**
12 + * Module dependencies.
13 + * @private
14 + */
15 +
16 +var Buffer = require('safe-buffer').Buffer
17 +var etag = require('etag')
18 +var fresh = require('fresh')
19 +var fs = require('fs')
20 +var ms = require('ms')
21 +var parseUrl = require('parseurl')
22 +var path = require('path')
23 +var resolve = path.resolve
24 +
25 +/**
26 + * Module exports.
27 + * @public
28 + */
29 +
30 +module.exports = favicon
31 +
32 +/**
33 + * Module variables.
34 + * @private
35 + */
36 +
37 +var ONE_YEAR_MS = 60 * 60 * 24 * 365 * 1000 // 1 year
38 +
39 +/**
40 + * Serves the favicon located by the given `path`.
41 + *
42 + * @public
43 + * @param {String|Buffer} path
44 + * @param {Object} [options]
45 + * @return {Function} middleware
46 + */
47 +
48 +function favicon (path, options) {
49 + var opts = options || {}
50 +
51 + var icon // favicon cache
52 + var maxAge = calcMaxAge(opts.maxAge)
53 +
54 + if (!path) {
55 + throw new TypeError('path to favicon.ico is required')
56 + }
57 +
58 + if (Buffer.isBuffer(path)) {
59 + icon = createIcon(Buffer.from(path), maxAge)
60 + } else if (typeof path === 'string') {
61 + path = resolveSync(path)
62 + } else {
63 + throw new TypeError('path to favicon.ico must be string or buffer')
64 + }
65 +
66 + return function favicon (req, res, next) {
67 + if (parseUrl(req).pathname !== '/favicon.ico') {
68 + next()
69 + return
70 + }
71 +
72 + if (req.method !== 'GET' && req.method !== 'HEAD') {
73 + res.statusCode = req.method === 'OPTIONS' ? 200 : 405
74 + res.setHeader('Allow', 'GET, HEAD, OPTIONS')
75 + res.setHeader('Content-Length', '0')
76 + res.end()
77 + return
78 + }
79 +
80 + if (icon) {
81 + send(req, res, icon)
82 + return
83 + }
84 +
85 + fs.readFile(path, function (err, buf) {
86 + if (err) return next(err)
87 + icon = createIcon(buf, maxAge)
88 + send(req, res, icon)
89 + })
90 + }
91 +}
92 +
93 +/**
94 + * Calculate the max-age from a configured value.
95 + *
96 + * @private
97 + * @param {string|number} val
98 + * @return {number}
99 + */
100 +
101 +function calcMaxAge (val) {
102 + var num = typeof val === 'string'
103 + ? ms(val)
104 + : val
105 +
106 + return num != null
107 + ? Math.min(Math.max(0, num), ONE_YEAR_MS)
108 + : ONE_YEAR_MS
109 +}
110 +
111 +/**
112 + * Create icon data from Buffer and max-age.
113 + *
114 + * @private
115 + * @param {Buffer} buf
116 + * @param {number} maxAge
117 + * @return {object}
118 + */
119 +
120 +function createIcon (buf, maxAge) {
121 + return {
122 + body: buf,
123 + headers: {
124 + 'Cache-Control': 'public, max-age=' + Math.floor(maxAge / 1000),
125 + 'ETag': etag(buf)
126 + }
127 + }
128 +}
129 +
130 +/**
131 + * Create EISDIR error.
132 + *
133 + * @private
134 + * @param {string} path
135 + * @return {Error}
136 + */
137 +
138 +function createIsDirError (path) {
139 + var error = new Error('EISDIR, illegal operation on directory \'' + path + '\'')
140 + error.code = 'EISDIR'
141 + error.errno = 28
142 + error.path = path
143 + error.syscall = 'open'
144 + return error
145 +}
146 +
147 +/**
148 + * Determine if the cached representation is fresh.
149 + *
150 + * @param {object} req
151 + * @param {object} res
152 + * @return {boolean}
153 + * @private
154 + */
155 +
156 +function isFresh (req, res) {
157 + return fresh(req.headers, {
158 + 'etag': res.getHeader('ETag'),
159 + 'last-modified': res.getHeader('Last-Modified')
160 + })
161 +}
162 +
163 +/**
164 + * Resolve the path to icon.
165 + *
166 + * @param {string} iconPath
167 + * @private
168 + */
169 +
170 +function resolveSync (iconPath) {
171 + var path = resolve(iconPath)
172 + var stat = fs.statSync(path)
173 +
174 + if (stat.isDirectory()) {
175 + throw createIsDirError(path)
176 + }
177 +
178 + return path
179 +}
180 +
181 +/**
182 + * Send icon data in response to a request.
183 + *
184 + * @private
185 + * @param {IncomingMessage} req
186 + * @param {OutgoingMessage} res
187 + * @param {object} icon
188 + */
189 +
190 +function send (req, res, icon) {
191 + // Set headers
192 + var headers = icon.headers
193 + var keys = Object.keys(headers)
194 + for (var i = 0; i < keys.length; i++) {
195 + var key = keys[i]
196 + res.setHeader(key, headers[key])
197 + }
198 +
199 + // Validate freshness
200 + if (isFresh(req, res)) {
201 + res.statusCode = 304
202 + res.end()
203 + return
204 + }
205 +
206 + // Send icon
207 + res.statusCode = 200
208 + res.setHeader('Content-Length', icon.body.length)
209 + res.setHeader('Content-Type', 'image/x-icon')
210 + res.end(icon.body)
211 +}
1 +{
2 + "_from": "serve-favicon@~2.4.5",
3 + "_id": "serve-favicon@2.4.5",
4 + "_inBundle": false,
5 + "_integrity": "sha512-s7F8h2NrslMkG50KxvlGdj+ApSwaLex0vexuJ9iFf3GLTIp1ph/l1qZvRe9T9TJEYZgmq72ZwJ2VYiAEtChknw==",
6 + "_location": "/serve-favicon",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "serve-favicon@~2.4.5",
12 + "name": "serve-favicon",
13 + "escapedName": "serve-favicon",
14 + "rawSpec": "~2.4.5",
15 + "saveSpec": null,
16 + "fetchSpec": "~2.4.5"
17 + },
18 + "_requiredBy": [
19 + "/"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.4.5.tgz",
22 + "_shasum": "49d9a46863153a9240691c893d2b0e7d85d6d436",
23 + "_spec": "serve-favicon@~2.4.5",
24 + "_where": "/home/ubuntu/OpenSource_Project",
25 + "author": {
26 + "name": "Douglas Christopher Wilson",
27 + "email": "doug@somethingdoug.com"
28 + },
29 + "bugs": {
30 + "url": "https://github.com/expressjs/serve-favicon/issues"
31 + },
32 + "bundleDependencies": false,
33 + "dependencies": {
34 + "etag": "~1.8.1",
35 + "fresh": "0.5.2",
36 + "ms": "2.0.0",
37 + "parseurl": "~1.3.2",
38 + "safe-buffer": "5.1.1"
39 + },
40 + "deprecated": false,
41 + "description": "favicon serving middleware with caching",
42 + "devDependencies": {
43 + "eslint": "3.19.0",
44 + "eslint-config-standard": "10.2.1",
45 + "eslint-plugin-import": "2.7.0",
46 + "eslint-plugin-markdown": "1.0.0-beta.6",
47 + "eslint-plugin-node": "5.1.1",
48 + "eslint-plugin-promise": "3.5.0",
49 + "eslint-plugin-standard": "3.0.1",
50 + "istanbul": "0.4.5",
51 + "mocha": "2.5.3",
52 + "supertest": "1.1.0",
53 + "temp-path": "1.0.0"
54 + },
55 + "engines": {
56 + "node": ">= 0.8.0"
57 + },
58 + "files": [
59 + "LICENSE",
60 + "HISTORY.md",
61 + "index.js"
62 + ],
63 + "homepage": "https://github.com/expressjs/serve-favicon#readme",
64 + "keywords": [
65 + "express",
66 + "favicon",
67 + "middleware"
68 + ],
69 + "license": "MIT",
70 + "name": "serve-favicon",
71 + "repository": {
72 + "type": "git",
73 + "url": "git+https://github.com/expressjs/serve-favicon.git"
74 + },
75 + "scripts": {
76 + "lint": "eslint --plugin markdown --ext js,md .",
77 + "test": "mocha --reporter spec --bail --check-leaks test/",
78 + "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
79 + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
80 + },
81 + "version": "2.4.5"
82 +}
1 { 1 {
2 - "requires": true, 2 + "name": "project",
3 + "version": "0.0.0",
3 "lockfileVersion": 1, 4 "lockfileVersion": 1,
5 + "requires": true,
4 "dependencies": { 6 "dependencies": {
5 "accepts": { 7 "accepts": {
6 "version": "1.3.4", 8 "version": "1.3.4",
...@@ -52,6 +54,14 @@ ...@@ -52,6 +54,14 @@
52 "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", 54 "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
53 "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" 55 "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
54 }, 56 },
57 + "basic-auth": {
58 + "version": "2.0.0",
59 + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
60 + "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=",
61 + "requires": {
62 + "safe-buffer": "5.1.1"
63 + }
64 + },
55 "bcrypt-pbkdf": { 65 "bcrypt-pbkdf": {
56 "version": "1.0.1", 66 "version": "1.0.1",
57 "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", 67 "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
...@@ -124,6 +134,15 @@ ...@@ -124,6 +134,15 @@
124 "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 134 "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
125 "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 135 "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
126 }, 136 },
137 + "cookie-parser": {
138 + "version": "1.4.3",
139 + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz",
140 + "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=",
141 + "requires": {
142 + "cookie": "0.3.1",
143 + "cookie-signature": "1.0.6"
144 + }
145 + },
127 "cookie-signature": { 146 "cookie-signature": {
128 "version": "1.0.6", 147 "version": "1.0.6",
129 "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 148 "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
...@@ -197,6 +216,11 @@ ...@@ -197,6 +216,11 @@
197 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 216 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
198 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 217 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
199 }, 218 },
219 + "ejs": {
220 + "version": "2.5.7",
221 + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz",
222 + "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo="
223 + },
200 "encodeurl": { 224 "encodeurl": {
201 "version": "1.0.1", 225 "version": "1.0.1",
202 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", 226 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
...@@ -464,6 +488,18 @@ ...@@ -464,6 +488,18 @@
464 "mime-db": "1.30.0" 488 "mime-db": "1.30.0"
465 } 489 }
466 }, 490 },
491 + "morgan": {
492 + "version": "1.9.0",
493 + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
494 + "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=",
495 + "requires": {
496 + "basic-auth": "2.0.0",
497 + "debug": "2.6.9",
498 + "depd": "1.1.1",
499 + "on-finished": "2.3.0",
500 + "on-headers": "1.0.1"
501 + }
502 + },
467 "ms": { 503 "ms": {
468 "version": "2.0.0", 504 "version": "2.0.0",
469 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 505 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
...@@ -487,6 +523,11 @@ ...@@ -487,6 +523,11 @@
487 "ee-first": "1.1.1" 523 "ee-first": "1.1.1"
488 } 524 }
489 }, 525 },
526 + "on-headers": {
527 + "version": "1.0.1",
528 + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
529 + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
530 + },
490 "parseurl": { 531 "parseurl": {
491 "version": "1.3.2", 532 "version": "1.3.2",
492 "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 533 "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
...@@ -591,6 +632,18 @@ ...@@ -591,6 +632,18 @@
591 "statuses": "1.3.1" 632 "statuses": "1.3.1"
592 } 633 }
593 }, 634 },
635 + "serve-favicon": {
636 + "version": "2.4.5",
637 + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.4.5.tgz",
638 + "integrity": "sha512-s7F8h2NrslMkG50KxvlGdj+ApSwaLex0vexuJ9iFf3GLTIp1ph/l1qZvRe9T9TJEYZgmq72ZwJ2VYiAEtChknw==",
639 + "requires": {
640 + "etag": "1.8.1",
641 + "fresh": "0.5.2",
642 + "ms": "2.0.0",
643 + "parseurl": "1.3.2",
644 + "safe-buffer": "5.1.1"
645 + }
646 + },
594 "serve-static": { 647 "serve-static": {
595 "version": "1.13.1", 648 "version": "1.13.1",
596 "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", 649 "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
......
1 +{
2 + "name": "project",
3 + "version": "0.0.0",
4 + "private": true,
5 + "scripts": {
6 + "start": "node ./bin/www"
7 + },
8 + "dependencies": {
9 + "body-parser": "~1.18.2",
10 + "cookie-parser": "~1.4.3",
11 + "debug": "~2.6.9",
12 + "ejs": "~2.5.7",
13 + "express": "^4.16.2",
14 + "morgan": "~1.9.0",
15 + "request": "^2.83.0",
16 + "serve-favicon": "~2.4.5"
17 + },
18 + "main": "app.js",
19 + "devDependencies": {},
20 + "author": "",
21 + "license": "ISC",
22 + "description": ""
23 +}
1 +var express = require('express');
2 +var app = express.Router();
3 +
4 +// Kakao Keyboard API
5 +app.get('/', function(req, res) {
6 + const menu = {
7 + "type": 'buttons',
8 + "buttons": ["/설정", "/시작"]};
9 +
10 + res.status(200).set({
11 + 'content-type': 'application/json'
12 + }).send(JSON.stringify(menu));
13 +});
14 +
15 +
16 +module.exports = app;
17 +
1 +var express = require('express');
2 +var request = require('request');
3 +var app = express.Router();
4 +
5 +// Naver Auth Key
6 +var client_id = '86rKmat0DijccSxKa01P';
7 +var client_secret = 'rMapNjB8DP';
8 +
9 +// Naver API URL
10 +var api_url = 'https://openapi.naver.com/v1/papago/n2mt';
11 +
12 +// Kakao Message API
13 +app.post('/', function(req, res) {
14 + const _obj = {
15 + user_key: req.body.user_key,
16 + type: req.body.type,
17 + content: req.body.content
18 + };
19 +
20 + console.log(_obj.content)
21 +
22 + if(_obj.content == '/시작'){
23 + res.set('content-type', 'application/json');
24 + res.json({
25 + "message": {
26 + "text": "언어를 설정하고 싶으면 /설정 이라고 타이핑 해주세요"
27 + },
28 + "keyboard": {
29 + "type": "text"
30 + }
31 + });
32 + }
33 +else{
34 + // Naver Papago Translate
35 + var options = {
36 + url: api_url,
37 + // 한국어(source : ko), 영어(target: en), 카톡에서 받는 메시지(text)
38 + form: {'source':'ko', 'target':'en', 'text':req.body.content},
39 + headers: {'X-Naver-Client-Id': client_id, 'X-Naver-Client-Secret': client_secret}
40 + };
41 +console.log('aa');
42 + // Naver Post API
43 + request.post(options, function(error, response, body){
44 + // Translate API Sucess
45 + if(!error && response.statusCode == 200){
46 + // JSON
47 + var objBody = JSON.parse(response.body);
48 + // Message 잘 찍히는지 확인
49 + console.log(objBody.message.result.translatedText);
50 +
51 + // Kakao Message API
52 + let massage = {
53 + "message": {
54 + // Naver API Translate 결과를 Kakao Message
55 + "text": objBody.message.result.translatedText
56 + },
57 + };
58 +
59 + // Kakao Message API 전송
60 + res.set({
61 + 'content-type': 'application/json'
62 + }).send(JSON.stringify(massage));
63 + }else{
64 + // Naver Message Error 발생
65 + res.status(response.statusCode).end();
66 + console.log('error = ' + response.statusCode);
67 +
68 + let massage = {
69 + "message": {
70 + "text": response.statusCode
71 + },
72 + };
73 +
74 + // Kakao에 Error Message
75 + res.set({
76 + 'content-type': 'application/json'
77 + }).send(JSON.stringify(massage));
78 + }
79 + });
80 +}
81 +});
82 +
83 +module.exports = app;
84 +