diff options
author | isaacs <i@izs.me> | 2013-04-07 02:39:48 +0400 |
---|---|---|
committer | isaacs <i@izs.me> | 2013-04-20 03:35:46 +0400 |
commit | eac726cb797d581f10ca627fd9dde1ac24c42363 (patch) | |
tree | a472a9d86adf2e433235c383819340d6f32b7505 /node_modules | |
parent | 40eaf458ecf49ca27c2773ebe3776fb6959afb66 (diff) |
request@2.16.6
Diffstat (limited to 'node_modules')
224 files changed, 32950 insertions, 824 deletions
diff --git a/node_modules/request/README.md b/node_modules/request/README.md index 1a55ac50b..039a10641 100644 --- a/node_modules/request/README.md +++ b/node_modules/request/README.md @@ -90,9 +90,51 @@ http.createServer(function (req, resp) { } }) ``` - You can still use intermediate proxies, the requests will still follow HTTP forwards, etc. +## Forms + +`request` supports `application/x-www-form-urlencoded` and `multipart/form-data` form uploads. For `multipart/related` refer to the `multipart` API. + +Url encoded forms are simple + +```javascript +request.post('http://service.com/upload', {form:{key:'value'}}) +// or +request.post('http://service.com/upload').form({key:'value'}) +``` + +For `multipart/form-data` we use the [form-data](https://github.com/felixge/node-form-data) library by [@felixge](https://github.com/felixge). You don't need to worry about piping the form object or setting the headers, `request` will handle that for you. + +```javascript +var r = request.post('http://service.com/upload') +var form = r.form() +form.append('my_field', 'my_value') +form.append('my_buffer', new Buffer([1, 2, 3])) +form.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png')) +form.append('remote_file', request('http://google.com/doodle.png')) +``` + +## HTTP Authentication + +```javascript +request.auth('username', 'password', false).get('http://some.server.com/'); +// or +request.get('http://some.server.com/', { + 'auth': { + 'user': 'username', + 'pass': 'password', + 'sendImmediately': false + } +}); +``` + +If passed as an option, `auth` should be a hash containing values `user` || `username`, `password` || `pass`, and `sendImmediately` (optional). The method form takes parameters `auth(username, password, sendImmediately)`. + +`sendImmediately` defaults to true, which will cause a basic authentication header to be sent. If `sendImmediately` is `false`, then `request` will retry with a proper authentication header after receiving a 401 response from the server (which must contain a `WWW-Authenticate` header indicating the required authentication method). + +Digest authentication is supported, but it only works with `sendImmediately` set to `false` (otherwise `request` will send basic authentication on the initial request, which will probably cause the request to fail). + ## OAuth Signing ```javascript @@ -106,14 +148,16 @@ var qs = require('querystring') , url = 'https://api.twitter.com/oauth/request_token' ; request.post({url:url, oauth:oauth}, function (e, r, body) { - // Assume by some stretch of magic you aquired the verifier + // Ideally, you would take the body in the response + // and construct a URL that a user clicks on (like a sign in button). + // The verifier is only available in the response after a user has + // verified with twitter that they are authorizing your app. var access_token = qs.parse(body) , oauth = { consumer_key: CONSUMER_KEY , consumer_secret: CONSUMER_SECRET , token: access_token.oauth_token - , verifier: VERIFIER - , token_secret: access_token.oauth_token_secret + , verifier: access_token.oauth_verifier } , url = 'https://api.twitter.com/oauth/access_token' ; @@ -149,8 +193,9 @@ The first argument can be either a url or an options object. The only required o * `qs` - object containing querystring values to be appended to the uri * `method` - http method, defaults to GET * `headers` - http headers, defaults to {} -* `body` - entity body for POST and PUT requests. Must be buffer or string. -* `form` - sets `body` but to querystring representation of value and adds `Content-type: application/x-www-form-urlencoded; charset=utf-8` header. +* `body` - entity body for PATCH, POST and PUT requests. Must be buffer or string. +* `form` - when passed an object this will set `body` but to a querystring representation of value and adds `Content-type: application/x-www-form-urlencoded; charset=utf-8` header. When passed no option a FormData instance is returned that will be piped to request. +* `auth` - A hash containing values `user` || `username`, `password` || `pass`, and `sendImmediately` (optional). See documentation above. * `json` - sets `body` but to JSON representation of value and adds `Content-type: application/json` header. Additionally, parses the response body as json. * `multipart` - (experimental) array of objects which contains their own headers and `body` attribute. Sends `multipart/related` request. See example below. * `followRedirect` - follow HTTP 3xx responses as redirects. defaults to true. @@ -162,8 +207,10 @@ The first argument can be either a url or an options object. The only required o * `timeout` - Integer containing the number of milliseconds to wait for a request to respond before aborting the request * `proxy` - An HTTP proxy to be used. Support proxy Auth with Basic Auth the same way it's supported with the `url` parameter by embedding the auth info in the uri. * `oauth` - Options for OAuth HMAC-SHA1 signing, see documentation above. +* `hawk` - Options for [Hawk signing](https://github.com/hueniverse/hawk). The `credentials` key must contain the necessary signing info, [see hawk docs for details](https://github.com/hueniverse/hawk#usage-example). * `strictSSL` - Set to `true` to require that SSL certificates be valid. Note: to use your own certificate authority, you need to specify an agent that was created with that ca as an option. * `jar` - Set to `false` if you don't want cookies to be remembered for future use or define your custom cookie jar (see examples section) +* `aws` - object containing aws signing information, should have the properties `key` and `secret` as well as `bucket` unless you're specifying your bucket as part of the path, or you are making a request that doesn't use a bucket (i.e. GET Services) The callback argument gets 3 arguments. The first is an error when applicable (usually from the http.Client option not the http.ClientRequest object). The second in an http.ClientResponse object. The third is the response body String or Buffer. @@ -184,6 +231,14 @@ Same as request() but defaults to `method: "PUT"`. request.put(url) ``` +### request.patch + +Same as request() but defaults to `method: "PATCH"`. + +```javascript +request.patch(url) +``` + ### request.post Same as request() but defaults to `method: "POST"`. diff --git a/node_modules/request/main.js b/node_modules/request/index.js index 8906b92aa..29284a1bb 100644..100755 --- a/node_modules/request/main.js +++ b/node_modules/request/index.js @@ -18,21 +18,25 @@ var http = require('http') , url = require('url') , util = require('util') , stream = require('stream') - , qs = require('querystring') - , mimetypes = require('./mimetypes') - , oauth = require('./oauth') - , uuid = require('./uuid') - , ForeverAgent = require('./forever') - , Cookie = require('./vendor/cookie') - , CookieJar = require('./vendor/cookie/jar') + , qs = require('qs') + , querystring = require('querystring') + , crypto = require('crypto') + + , oauth = require('oauth-sign') + , hawk = require('hawk') + , aws = require('aws-sign') + , uuid = require('node-uuid') + , mime = require('mime') + , tunnel = require('tunnel-agent') + , safeStringify = require('json-stringify-safe') + + , ForeverAgent = require('forever-agent') + , FormData = require('form-data') + + , Cookie = require('cookie-jar') + , CookieJar = Cookie.Jar , cookieJar = new CookieJar - , tunnel = require('./tunnel') - , aws = require('./aws') ; - -if (process.logging) { - var log = process.logging('request') -} try { https = require('https') @@ -42,10 +46,23 @@ try { tls = require('tls') } catch (e) {} +var debug +if (/\brequest\b/.test(process.env.NODE_DEBUG)) { + debug = function() { + console.error('REQUEST %s', util.format.apply(util, arguments)) + } +} else { + debug = function() {} +} + function toBase64 (str) { return (new Buffer(str || "", "ascii")).toString("base64") } +function md5 (str) { + return crypto.createHash('md5').update(str).digest('hex') +} + // Hacky fix for pre-0.4.4 https if (https && !https.Agent) { https.Agent = function (options) { @@ -98,18 +115,22 @@ function Request (options) { } } } - options = copy(options) this.init(options) } util.inherits(Request, stream.Stream) Request.prototype.init = function (options) { + // init() contains all the code to setup the request object. + // the actual outgoing request is not started until start() is called + // this function is called from both the constructor and on redirect. var self = this - if (!options) options = {} - if (process.env.NODE_DEBUG && /request/.test(process.env.NODE_DEBUG)) console.error('REQUEST', options) + + self.method = options.method || 'GET' + + debug(options) if (!self.pool && self.pool !== false) self.pool = globalPool - self.dests = [] + self.dests = self.dests || [] self.__isRequestRequest = true // Protect against double callback @@ -117,8 +138,8 @@ Request.prototype.init = function (options) { self._callback = self.callback self.callback = function () { if (self._callbackCalled) return // Print a warning maybe? - self._callback.apply(self, arguments) self._callbackCalled = true + self._callback.apply(self, arguments) } self.on('error', self.callback.bind()) self.on('complete', self.callback.bind(self, null)) @@ -131,10 +152,12 @@ Request.prototype.init = function (options) { } if (!self.uri) { - throw new Error("options.uri is a required argument") + // this will throw if unhandled but is handleable when in a redirect + return self.emit('error', new Error("options.uri is a required argument")) } else { if (typeof self.uri == "string") self.uri = url.parse(self.uri) } + if (self.proxy) { if (typeof self.proxy == 'string') self.proxy = url.parse(self.proxy) @@ -145,7 +168,9 @@ Request.prototype.init = function (options) { var tunnelOptions = { proxy: { host: self.proxy.hostname , port: +self.proxy.port - , proxyAuth: self.proxy.auth } + , proxyAuth: self.proxy.auth + , headers: { Host: self.uri.hostname + ':' + + (self.uri.port || self.uri.protocol === 'https:' ? 443 : 80) }} , ca: this.ca } self.agent = tunnelFn(tunnelOptions) @@ -171,14 +196,14 @@ Request.prototype.init = function (options) { self._redirectsFollowed = self._redirectsFollowed || 0 self.maxRedirects = (self.maxRedirects !== undefined) ? self.maxRedirects : 10 self.followRedirect = (self.followRedirect !== undefined) ? self.followRedirect : true - self.followAllRedirects = (self.followAllRedirects !== undefined) ? self.followAllRedirects : false; + self.followAllRedirects = (self.followAllRedirects !== undefined) ? self.followAllRedirects : false if (self.followRedirect || self.followAllRedirects) self.redirects = self.redirects || [] self.headers = self.headers ? copy(self.headers) : {} self.setHost = false - if (!self.headers.host) { + if (!(self.headers.host || self.headers.Host)) { self.headers.host = self.uri.hostname if (self.uri.port) { if ( !(self.uri.port === 80 && self.uri.protocol === 'http:') && @@ -207,8 +232,7 @@ Request.prototype.init = function (options) { self.clientErrorHandler = function (error) { if (self._aborted) return - if (self.setHost) delete self.headers.host - if (self.req._reusedSocket && error.code === 'ECONNRESET' + if (self.req && self.req._reusedSocket && error.code === 'ECONNRESET' && self.agent.addRequestNoreuse) { self.agent = { addRequest: self.agent.addRequestNoreuse.bind(self.agent) } self.start() @@ -237,7 +261,19 @@ Request.prototype.init = function (options) { if (options.form) { self.form(options.form) } + + if (options.qs) self.qs(options.qs) + + if (self.uri.path) { + self.path = self.uri.path + } else { + self.path = self.uri.pathname + (self.uri.search || "") + } + + if (self.path.length === 0) self.path = '/' + + // Auth must happen last in case signing is dependent on other headers if (options.oauth) { self.oauth(options.oauth) } @@ -245,24 +281,27 @@ Request.prototype.init = function (options) { if (options.aws) { self.aws(options.aws) } + + if (options.hawk) { + self.hawk(options.hawk) + } + + if (options.auth) { + self.auth( + options.auth.user || options.auth.username, + options.auth.pass || options.auth.password, + options.auth.sendImmediately) + } if (self.uri.auth && !self.headers.authorization) { - self.headers.authorization = "Basic " + toBase64(self.uri.auth.split(':').map(function(item){ return qs.unescape(item)}).join(':')) + var authPieces = self.uri.auth.split(':').map(function(item){ return querystring.unescape(item) }) + self.auth(authPieces[0], authPieces[1], true) } if (self.proxy && self.proxy.auth && !self.headers['proxy-authorization'] && !self.tunnel) { - self.headers['proxy-authorization'] = "Basic " + toBase64(self.proxy.auth.split(':').map(function(item){ return qs.unescape(item)}).join(':')) - } - - if (options.qs) self.qs(options.qs) - - if (self.uri.path) { - self.path = self.uri.path - } else { - self.path = self.uri.pathname + (self.uri.search || "") + self.headers['proxy-authorization'] = "Basic " + toBase64(self.proxy.auth.split(':').map(function(item){ return querystring.unescape(item)}).join(':')) } - if (self.path.length === 0) self.path = '/' - + if (self.proxy && !self.tunnel) self.path = (self.uri.protocol + '//' + self.uri.host + self.path) if (options.json) { @@ -287,6 +326,7 @@ Request.prototype.init = function (options) { length = self.body.length } if (length) { + if(!self.headers['content-length'] && !self.headers['Content-Length']) self.headers['content-length'] = length } else { throw new Error('Argument error, options.body.') @@ -299,7 +339,7 @@ Request.prototype.init = function (options) { ; self.httpModule = httpModules[protocol] || defaultModules[protocol] - if (!self.httpModule) throw new Error("Invalid protocol") + if (!self.httpModule) return this.emit('error', new Error("Invalid protocol")) if (options.ca) self.ca = options.ca @@ -314,6 +354,10 @@ Request.prototype.init = function (options) { self.agentClass = self.httpModule.Agent } } + + if (self.strictSSL === false) { + self.rejectUnauthorized = false + } if (self.pool === false) { self.agent = false @@ -334,7 +378,7 @@ Request.prototype.init = function (options) { self.src = src if (isReadStream(src)) { if (!self.headers['content-type'] && !self.headers['Content-Type']) - self.headers['content-type'] = mimetypes.lookup(src.path.slice(src.path.lastIndexOf('.')+1)) + self.headers['content-type'] = mime.lookup(src.path) } else { if (src.headers) { for (var i in src.headers) { @@ -343,6 +387,8 @@ Request.prototype.init = function (options) { } } } + if (self._json && !self.headers['content-type'] && !self.headers['Content-Type']) + self.headers['content-type'] = 'application/json' if (src.method && !self.method) { self.method = src.method } @@ -356,6 +402,10 @@ Request.prototype.init = function (options) { process.nextTick(function () { if (self._aborted) return + if (self._form) { + self.setHeaders(self._form.getHeaders()) + self._form.pipe(self) + } if (self.body) { if (Array.isArray(self.body)) { self.body.forEach(function (part) { @@ -370,9 +420,9 @@ Request.prototype.init = function (options) { self.requestBodyStream.pipe(self) } else if (!self.src) { if (self.method !== 'GET' && typeof self.method !== 'undefined') { - self.headers['content-length'] = 0; + self.headers['content-length'] = 0 } - self.end(); + self.end() } self.ntick = true }) @@ -393,7 +443,7 @@ Request.prototype._updateProtocol = function () { var tunnelFn = self.proxy.protocol === 'http:' ? tunnel.httpsOverHttp : tunnel.httpsOverHttps var tunnelOptions = { proxy: { host: self.proxy.hostname - , post: +self.proxy.port + , port: +self.proxy.port , proxyAuth: self.proxy.auth } , ca: self.ca } self.agent = tunnelFn(tunnelOptions) @@ -417,7 +467,6 @@ Request.prototype._updateProtocol = function () { if (self.agent) self.agent = self.getAgent() } else { - if (log) log('previously https, now http') // previously was doing https, now doing http // stop any tunneling. if (self.tunnel) self.tunnel = false @@ -451,6 +500,12 @@ Request.prototype.getAgent = function () { } } if (this.ca) options.ca = this.ca + if (typeof this.rejectUnauthorized !== 'undefined') options.rejectUnauthorized = this.rejectUnauthorized + + if (this.cert && this.key) { + options.key = this.key + options.cert = this.cert + } var poolKey = '' @@ -470,10 +525,20 @@ Request.prototype.getAgent = function () { // ca option is only relevant if proxy or destination are https var proxy = this.proxy if (typeof proxy === 'string') proxy = url.parse(proxy) - var caRelevant = (proxy && proxy.protocol === 'https:') || this.uri.protocol === 'https:' - if (options.ca && caRelevant) { - if (poolKey) poolKey += ':' - poolKey += options.ca + var isHttps = (proxy && proxy.protocol === 'https:') || this.uri.protocol === 'https:' + if (isHttps) { + if (options.ca) { + if (poolKey) poolKey += ':' + poolKey += options.ca + } + + if (typeof options.rejectUnauthorized !== 'undefined') { + if (poolKey) poolKey += ':' + poolKey += options.rejectUnauthorized + } + + if (options.cert) + poolKey += options.cert.toString('ascii') + options.key.toString('ascii') } if (!poolKey && Agent === this.httpModule.Agent && this.httpModule.globalAgent) { @@ -491,6 +556,8 @@ Request.prototype.getAgent = function () { } Request.prototype.start = function () { + // start() is called once we are ready to send the outgoing HTTP request. + // this is usually called on the first write(), end() or on nextTick() var self = this if (self._aborted) return @@ -498,159 +565,21 @@ Request.prototype.start = function () { self._started = true self.method = self.method || 'GET' self.href = self.uri.href - if (log) log('%method %href', self) - if (self.src && self.src.stat && self.src.stat.size) { + if (self.src && self.src.stat && self.src.stat.size && !self.headers['content-length'] && !self.headers['Content-Length']) { self.headers['content-length'] = self.src.stat.size } if (self._aws) { self.aws(self._aws, true) } - self.req = self.httpModule.request(self, function (response) { - if (response.connection.listeners('error').indexOf(self._parserErrorHandler) === -1) { - response.connection.once('error', self._parserErrorHandler) - } - if (self._aborted) return response.resume() - if (self._paused) response.pause() - else response.resume() - - self.response = response - response.request = self - response.toJSON = toJSON - - if (self.httpModule === https && - self.strictSSL && - !response.client.authorized) { - var sslErr = response.client.authorizationError - self.emit('error', new Error('SSL Error: '+ sslErr)) - return - } - - if (self.setHost) delete self.headers.host - if (self.timeout && self.timeoutTimer) { - clearTimeout(self.timeoutTimer) - self.timeoutTimer = null - } - - var addCookie = function (cookie) { - if (self._jar) self._jar.add(new Cookie(cookie)) - else cookieJar.add(new Cookie(cookie)) - } - - if (response.headers['set-cookie'] && (!self._disableCookies)) { - if (Array.isArray(response.headers['set-cookie'])) response.headers['set-cookie'].forEach(addCookie) - else addCookie(response.headers['set-cookie']) - } - - if (response.statusCode >= 300 && response.statusCode < 400 && - (self.followAllRedirects || - (self.followRedirect && (self.method !== 'PUT' && self.method !== 'POST' && self.method !== 'DELETE'))) && - response.headers.location) { - if (self._redirectsFollowed >= self.maxRedirects) { - self.emit('error', new Error("Exceeded maxRedirects. Probably stuck in a redirect loop.")) - return - } - self._redirectsFollowed += 1 - - if (!isUrl.test(response.headers.location)) { - response.headers.location = url.resolve(self.uri.href, response.headers.location) - } + // We have a method named auth, which is completely different from the http.request + // auth option. If we don't remove it, we're gonna have a bad time. + var reqOptions = copy(self) + delete reqOptions.auth - var uriPrev = self.uri - self.uri = url.parse(response.headers.location) - - // handle the case where we change protocol from https to http or vice versa - if (self.uri.protocol !== uriPrev.protocol) { - self._updateProtocol() - } - - self.redirects.push( - { statusCode : response.statusCode - , redirectUri: response.headers.location - } - ) - if (self.followAllRedirects) self.method = 'GET' - // self.method = 'GET'; // Force all redirects to use GET || commented out fixes #215 - delete self.req - delete self.agent - delete self._started - delete self.body - if (self.headers) { - delete self.headers.host - } - if (log) log('Redirect to %uri', self) - self.init() - return // Ignore the rest of the response - } else { - self._redirectsFollowed = self._redirectsFollowed || 0 - // Be a good stream and emit end when the response is finished. - // Hack to emit end on close because of a core bug that never fires end - response.on('close', function () { - if (!self._ended) self.response.emit('end') - }) - - if (self.encoding) { - if (self.dests.length !== 0) { - console.error("Ingoring encoding parameter as this stream is being piped to another stream which makes the encoding option invalid.") - } else { - response.setEncoding(self.encoding) - } - } - - self.dests.forEach(function (dest) { - self.pipeDest(dest) - }) - - response.on("data", function (chunk) { - self._destdata = true - self.emit("data", chunk) - }) - response.on("end", function (chunk) { - self._ended = true - self.emit("end", chunk) - }) - response.on("close", function () {self.emit("close")}) - - self.emit('response', response) - - if (self.callback) { - var buffer = [] - var bodyLen = 0 - self.on("data", function (chunk) { - buffer.push(chunk) - bodyLen += chunk.length - }) - self.on("end", function () { - if (self._aborted) return - - if (buffer.length && Buffer.isBuffer(buffer[0])) { - var body = new Buffer(bodyLen) - var i = 0 - buffer.forEach(function (chunk) { - chunk.copy(body, i, 0, chunk.length) - i += chunk.length - }) - if (self.encoding === null) { - response.body = body - } else { - response.body = body.toString(self.encoding) - } - } else if (buffer.length) { - response.body = buffer.join('') - } - - if (self._json) { - try { - response.body = JSON.parse(response.body) - } catch (e) {} - } - - self.emit('complete', response, response.body) - }) - } - } - }) + debug('make request', self.uri.href) + self.req = self.httpModule.request(reqOptions, self.onResponse.bind(self)) if (self.timeout && !self.timeoutTimer) { self.timeoutTimer = setTimeout(function () { @@ -679,13 +608,260 @@ Request.prototype.start = function () { self.emit('drain') }) self.on('end', function() { - self.req.connection.removeListener('error', self._parserErrorHandler) + if ( self.req.connection ) self.req.connection.removeListener('error', self._parserErrorHandler) }) self.emit('request', self.req) } +Request.prototype.onResponse = function (response) { + var self = this + debug('onResponse', self.uri.href, response.statusCode, response.headers) + response.on('end', function() { + debug('response end', self.uri.href, response.statusCode, response.headers) + }); + + if (response.connection.listeners('error').indexOf(self._parserErrorHandler) === -1) { + response.connection.once('error', self._parserErrorHandler) + } + if (self._aborted) { + debug('aborted', self.uri.href) + response.resume() + return + } + if (self._paused) response.pause() + else response.resume() + + self.response = response + response.request = self + response.toJSON = toJSON + + // XXX This is different on 0.10, because SSL is strict by default + if (self.httpModule === https && + self.strictSSL && + !response.client.authorized) { + debug('strict ssl error', self.uri.href) + var sslErr = response.client.authorizationError + self.emit('error', new Error('SSL Error: '+ sslErr)) + return + } + + if (self.setHost) delete self.headers.host + if (self.timeout && self.timeoutTimer) { + clearTimeout(self.timeoutTimer) + self.timeoutTimer = null + } + + var addCookie = function (cookie) { + if (self._jar) self._jar.add(new Cookie(cookie)) + else cookieJar.add(new Cookie(cookie)) + } + + if (response.headers['set-cookie'] && (!self._disableCookies)) { + if (Array.isArray(response.headers['set-cookie'])) response.headers['set-cookie'].forEach(addCookie) + else addCookie(response.headers['set-cookie']) + } + + var redirectTo = null + if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) { + debug('redirect', response.headers.location) + + if (self.followAllRedirects) { + redirectTo = response.headers.location + } else if (self.followRedirect) { + switch (self.method) { + case 'PATCH': + case 'PUT': + case 'POST': + case 'DELETE': + // Do not follow redirects + break + default: + redirectTo = response.headers.location + break + } + } + } else if (response.statusCode == 401 && self._hasAuth && !self._sentAuth) { + var authHeader = response.headers['www-authenticate'] + var authVerb = authHeader && authHeader.split(' ')[0] + debug('reauth', authVerb) + + switch (authVerb) { + case 'Basic': + self.auth(self._user, self._pass, true) + redirectTo = self.uri + break + + case 'Digest': + // TODO: More complete implementation of RFC 2617. For reference: + // http://tools.ietf.org/html/rfc2617#section-3 + // https://github.com/bagder/curl/blob/master/lib/http_digest.c + + var matches = authHeader.match(/([a-z0-9_-]+)="([^"]+)"/gi) + var challenge = {} + + for (var i = 0; i < matches.length; i++) { + var eqPos = matches[i].indexOf('=') + var key = matches[i].substring(0, eqPos) + var quotedValue = matches[i].substring(eqPos + 1) + challenge[key] = quotedValue.substring(1, quotedValue.length - 1) + } + + var ha1 = md5(self._user + ':' + challenge.realm + ':' + self._pass) + var ha2 = md5(self.method + ':' + self.uri.path) + var digestResponse = md5(ha1 + ':' + challenge.nonce + ':1::auth:' + ha2) + var authValues = { + username: self._user, + realm: challenge.realm, + nonce: challenge.nonce, + uri: self.uri.path, + qop: challenge.qop, + response: digestResponse, + nc: 1, + cnonce: '' + } + + authHeader = [] + for (var k in authValues) { + authHeader.push(k + '="' + authValues[k] + '"') + } + authHeader = 'Digest ' + authHeader.join(', ') + self.setHeader('authorization', authHeader) + self._sentAuth = true + + redirectTo = self.uri + break + } + } + + if (redirectTo) { + debug('redirect to', redirectTo) + + // ignore any potential response body. it cannot possibly be useful + // to us at this point. + if (self._paused) response.resume() + + if (self._redirectsFollowed >= self.maxRedirects) { + self.emit('error', new Error("Exceeded maxRedirects. Probably stuck in a redirect loop "+self.uri.href)) + return + } + self._redirectsFollowed += 1 + + if (!isUrl.test(redirectTo)) { + redirectTo = url.resolve(self.uri.href, redirectTo) + } + + var uriPrev = self.uri + self.uri = url.parse(redirectTo) + + // handle the case where we change protocol from https to http or vice versa + if (self.uri.protocol !== uriPrev.protocol) { + self._updateProtocol() + } + + self.redirects.push( + { statusCode : response.statusCode + , redirectUri: redirectTo + } + ) + if (self.followAllRedirects && response.statusCode != 401) self.method = 'GET' + // self.method = 'GET' // Force all redirects to use GET || commented out fixes #215 + delete self.src + delete self.req + delete self.agent + delete self._started + if (response.statusCode != 401) { + delete self.body + delete self._form + } + if (self.headers) { + delete self.headers.host + delete self.headers['content-type'] + delete self.headers['content-length'] + } + self.init() + return // Ignore the rest of the response + } else { + self._redirectsFollowed = self._redirectsFollowed || 0 + // Be a good stream and emit end when the response is finished. + // Hack to emit end on close because of a core bug that never fires end + response.on('close', function () { + if (!self._ended) self.response.emit('end') + }) + + if (self.encoding) { + if (self.dests.length !== 0) { + console.error("Ingoring encoding parameter as this stream is being piped to another stream which makes the encoding option invalid.") + } else { + response.setEncoding(self.encoding) + } + } + + self.dests.forEach(function (dest) { + self.pipeDest(dest) + }) + + response.on("data", function (chunk) { + self._destdata = true + self.emit("data", chunk) + }) + response.on("end", function (chunk) { + self._ended = true + self.emit("end", chunk) + }) + response.on("close", function () {self.emit("close")}) + + self.emit('response', response) + + if (self.callback) { + var buffer = [] + var bodyLen = 0 + self.on("data", function (chunk) { + buffer.push(chunk) + bodyLen += chunk.length + }) + self.on("end", function () { + debug('end event', self.uri.href) + if (self._aborted) { + debug('aborted', self.uri.href) + return + } + + if (buffer.length && Buffer.isBuffer(buffer[0])) { + debug('has body', self.uri.href, bodyLen) + var body = new Buffer(bodyLen) + var i = 0 + buffer.forEach(function (chunk) { + chunk.copy(body, i, 0, chunk.length) + i += chunk.length + }) + if (self.encoding === null) { + response.body = body + } else { + response.body = body.toString(self.encoding) + } + } else if (buffer.length) { + // The UTF8 BOM [0xEF,0xBB,0xBF] is converted to [0xFE,0xFF] in the JS UTC16/UCS2 representation. + // Strip this value out when the encoding is set to 'utf8', as upstream consumers won't expect it and it breaks JSON.parse(). + if (self.encoding === 'utf8' && buffer[0].length > 0 && buffer[0][0] === "\uFEFF") { + buffer[0] = buffer[0].substring(1) + } + response.body = buffer.join('') + } + + if (self._json) { + try { + response.body = JSON.parse(response.body) + } catch (e) {} + } + debug('emitting complete', self.uri.href) + self.emit('complete', response, response.body) + }) + } + } + debug('finish init function', self.uri.href) +} Request.prototype.abort = function () { - this._aborted = true; + this._aborted = true if (this.req) { this.req.abort() @@ -734,6 +910,10 @@ Request.prototype.qs = function (q, clobber) { for (var i in q) { base[i] = q[i] } + + if (qs.stringify(base) === ''){ + return this + } this.uri = url.parse(this.uri.href.split('?')[0] + '?' + qs.stringify(base)) this.url = this.uri @@ -741,18 +921,23 @@ Request.prototype.qs = function (q, clobber) { return this } Request.prototype.form = function (form) { - this.headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8' - this.body = qs.stringify(form).toString('utf8') - return this + if (form) { + this.headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8' + this.body = qs.stringify(form).toString('utf8') + return this + } + // create form-data object + this._form = new FormData() + return this._form } Request.prototype.multipart = function (multipart) { var self = this self.body = [] if (!self.headers['content-type']) { - self.headers['content-type'] = 'multipart/related; boundary=' + self.boundary; + self.headers['content-type'] = 'multipart/related; boundary=' + self.boundary } else { - self.headers['content-type'] = self.headers['content-type'].split(';')[0] + '; boundary=' + self.boundary; + self.headers['content-type'] = self.headers['content-type'].split(';')[0] + '; boundary=' + self.boundary } if (!multipart.forEach) throw new Error('Argument error, options.multipart.') @@ -778,13 +963,46 @@ Request.prototype.multipart = function (multipart) { return self } Request.prototype.json = function (val) { - this.setHeader('content-type', 'application/json') - this.setHeader('accept', 'application/json') + var self = this; + var setAcceptHeader = function() { + if (!self.headers['accept'] && !self.headers['Accept']) { + self.setHeader('accept', 'application/json') + } + } + setAcceptHeader(); this._json = true if (typeof val === 'boolean') { - if (typeof this.body === 'object') this.body = JSON.stringify(this.body) + if (typeof this.body === 'object') { + setAcceptHeader(); + this.body = safeStringify(this.body) + self.setHeader('content-type', 'application/json') + } } else { - this.body = JSON.stringify(val) + setAcceptHeader(); + this.body = safeStringify(val) + self.setHeader('content-type', 'application/json') + } + return this +} +function getHeader(name, headers) { + var result, re, match + Object.keys(headers).forEach(function (key) { + re = new RegExp(name, 'i') + match = key.match(re) + if (match) result = headers[key] + }) + return result +} +Request.prototype.auth = function (user, pass, sendImmediately) { + if (typeof user !== 'string' || typeof pass !== 'string') { + throw new Error('auth() received invalid user or password') + } + this._user = user + this._pass = pass + this._hasAuth = true + if (sendImmediately || typeof sendImmediately == 'undefined') { + this.setHeader('authorization', 'Basic ' + toBase64(user + ':' + pass)) + this._sentAuth = true } return this } @@ -795,21 +1013,34 @@ Request.prototype.aws = function (opts, now) { } var date = new Date() this.setHeader('date', date.toUTCString()) - this.setHeader('authorization', aws.authorization( + var auth = { key: opts.key , secret: opts.secret - , verb: this.method + , verb: this.method.toUpperCase() , date: date - , resource: aws.canonicalizeResource('/' + opts.bucket + this.path) - , contentType: this.headers['content-type'] || '' - , md5: this.headers['content-md5'] || '' + , contentType: getHeader('content-type', this.headers) || '' + , md5: getHeader('content-md5', this.headers) || '' , amazonHeaders: aws.canonicalizeHeaders(this.headers) } - )) + if (opts.bucket && this.path) { + auth.resource = '/' + opts.bucket + this.path + } else if (opts.bucket && !this.path) { + auth.resource = '/' + opts.bucket + } else if (!opts.bucket && this.path) { + auth.resource = this.path + } else if (!opts.bucket && !this.path) { + auth.resource = '/' + } + auth.resource = aws.canonicalizeResource(auth.resource) + this.setHeader('authorization', aws.authorization(auth)) return this } +Request.prototype.hawk = function (opts) { + this.headers.Authorization = hawk.client.header(this.uri, this.method, opts).field +} + Request.prototype.oauth = function (_oauth) { var form if (this.headers['content-type'] && @@ -826,7 +1057,7 @@ Request.prototype.oauth = function (_oauth) { for (var i in form) oa[i] = form[i] for (var i in _oauth) oa['oauth_'+i] = _oauth[i] if (!oa.oauth_version) oa.oauth_version = '1.0' - if (!oa.oauth_timestamp) oa.oauth_timestamp = Math.floor( (new Date()).getTime() / 1000 ).toString() + if (!oa.oauth_timestamp) oa.oauth_timestamp = Math.floor( Date.now() / 1000 ).toString() if (!oa.oauth_nonce) oa.oauth_nonce = uuid().replace(/-/g, '') oa.oauth_signature_method = 'HMAC-SHA1' @@ -835,7 +1066,8 @@ Request.prototype.oauth = function (_oauth) { delete oa.oauth_consumer_secret var token_secret = oa.oauth_token_secret delete oa.oauth_token_secret - + var timestamp = oa.oauth_timestamp + var baseurl = this.uri.protocol + '//' + this.uri.host + this.uri.pathname var signature = oauth.hmacsign(this.method, baseurl, oa, consumer_secret, token_secret) @@ -845,12 +1077,13 @@ Request.prototype.oauth = function (_oauth) { // skip } else { delete oa['oauth_'+i] - delete oa[i] + if (i !== 'x_auth_mode') delete oa[i] } } - this.headers.Authorization = + oa.oauth_timestamp = timestamp + this.headers.Authorization = 'OAuth '+Object.keys(oa).sort().map(function (i) {return i+'="'+oauth.rfc3986(oa[i])+'"'}).join(',') - this.headers.Authorization += ',oauth_signature="'+oauth.rfc3986(signature)+'"' + this.headers.Authorization += ',oauth_signature="' + oauth.rfc3986(signature) + '"' return this } Request.prototype.jar = function (jar) { @@ -862,8 +1095,8 @@ Request.prototype.jar = function (jar) { if (jar === false) { // disable cookies - cookies = false; - this._disableCookies = true; + cookies = false + this._disableCookies = true } else if (jar) { // fetch cookie from the user defined cookie jar cookies = jar.get({ url: this.uri.href }) @@ -926,68 +1159,74 @@ Request.prototype.resume = function () { } Request.prototype.destroy = function () { if (!this._ended) this.end() + else if (this.response) this.response.destroy() } -// organize params for post, put, head, del +// organize params for patch, post, put, head, del function initParams(uri, options, callback) { - if ((typeof options === 'function') && !callback) callback = options; + if ((typeof options === 'function') && !callback) callback = options if (options && typeof options === 'object') { - options.uri = uri; + options.uri = uri } else if (typeof uri === 'string') { - options = {uri:uri}; + options = {uri:uri} } else { - options = uri; - uri = options.uri; + options = uri + uri = options.uri } - return { uri: uri, options: options, callback: callback }; + return { uri: uri, options: options, callback: callback } } function request (uri, options, callback) { if (typeof uri === 'undefined') throw new Error('undefined is not a valid uri or options object.') - if ((typeof options === 'function') && !callback) callback = options; + if ((typeof options === 'function') && !callback) callback = options if (options && typeof options === 'object') { - options.uri = uri; + options.uri = uri } else if (typeof uri === 'string') { - options = {uri:uri}; + options = {uri:uri} } else { - options = uri; + options = uri } - if (callback) options.callback = callback; + options = copy(options) + + if (callback) options.callback = callback var r = new Request(options) return r } module.exports = request -request.initParams = initParams; +request.debug = process.env.NODE_DEBUG && /request/.test(process.env.NODE_DEBUG) + +request.initParams = initParams request.defaults = function (options, requester) { var def = function (method) { var d = function (uri, opts, callback) { - var params = initParams(uri, opts, callback); + var params = initParams(uri, opts, callback) for (var i in options) { if (params.options[i] === undefined) params.options[i] = options[i] } if(typeof requester === 'function') { if(method === request) { - method = requester; + method = requester } else { - params.options._requester = requester; + params.options._requester = requester } } - return method(params.options, params.callback); + return method(params.options, params.callback) } - return d; + return d } var de = def(request) de.get = def(request.get) + de.patch = def(request.patch) de.post = def(request.post) de.put = def(request.put) de.head = def(request.head) de.del = def(request.del) de.cookie = def(request.cookie) - de.jar = def(request.jar) + de.jar = request.jar return de } @@ -1005,17 +1244,22 @@ request.forever = function (agentOptions, optionsArg) { request.get = request request.post = function (uri, options, callback) { - var params = initParams(uri, options, callback); - params.options.method = 'POST'; + var params = initParams(uri, options, callback) + params.options.method = 'POST' return request(params.uri || null, params.options, params.callback) } request.put = function (uri, options, callback) { - var params = initParams(uri, options, callback); + var params = initParams(uri, options, callback) params.options.method = 'PUT' return request(params.uri || null, params.options, params.callback) } +request.patch = function (uri, options, callback) { + var params = initParams(uri, options, callback) + params.options.method = 'PATCH' + return request(params.uri || null, params.options, params.callback) +} request.head = function (uri, options, callback) { - var params = initParams(uri, options, callback); + var params = initParams(uri, options, callback) params.options.method = 'HEAD' if (params.options.body || params.options.requestBodyStream || @@ -1026,10 +1270,10 @@ request.head = function (uri, options, callback) { return request(params.uri || null, params.options, params.callback) } request.del = function (uri, options, callback) { - var params = initParams(uri, options, callback); + var params = initParams(uri, options, callback) params.options.method = 'DELETE' if(typeof params.options._requester === 'function') { - request = params.options._requester; + request = params.options._requester } return request(params.uri || null, params.options, params.callback) } @@ -1078,8 +1322,7 @@ function getSafe (self, uuid) { } function toJSON () { - return getSafe(this, (((1+Math.random())*0x10000)|0).toString(16)) + return getSafe(this, '__' + (((1+Math.random())*0x10000)|0).toString(16)) } Request.prototype.toJSON = toJSON - diff --git a/node_modules/request/mimetypes.js b/node_modules/request/mimetypes.js deleted file mode 100644 index 59b21b419..000000000 --- a/node_modules/request/mimetypes.js +++ /dev/null @@ -1,152 +0,0 @@ -// from http://github.com/felixge/node-paperboy -exports.types = { - "3gp":"video/3gpp", - "aiff":"audio/x-aiff", - "arj":"application/x-arj-compressed", - "asf":"video/x-ms-asf", - "asx":"video/x-ms-asx", - "au":"audio/ulaw", - "avi":"video/x-msvideo", - "bcpio":"application/x-bcpio", - "ccad":"application/clariscad", - "cod":"application/vnd.rim.cod", - "com":"application/x-msdos-program", - "cpio":"application/x-cpio", - "cpt":"application/mac-compactpro", - "csh":"application/x-csh", - "css":"text/css", - "deb":"application/x-debian-package", - "dl":"video/dl", - "doc":"application/msword", - "drw":"application/drafting", - "dvi":"application/x-dvi", - "dwg":"application/acad", - "dxf":"application/dxf", - "dxr":"application/x-director", - "etx":"text/x-setext", - "ez":"application/andrew-inset", - "fli":"video/x-fli", - "flv":"video/x-flv", - "gif":"image/gif", - "gl":"video/gl", - "gtar":"application/x-gtar", - "gz":"application/x-gzip", - "hdf":"application/x-hdf", - "hqx":"application/mac-binhex40", - "html":"text/html", - "ice":"x-conference/x-cooltalk", - "ico":"image/x-icon", - "ief":"image/ief", - "igs":"model/iges", - "ips":"application/x-ipscript", - "ipx":"application/x-ipix", - "jad":"text/vnd.sun.j2me.app-descriptor", - "jar":"application/java-archive", - "jpeg":"image/jpeg", - "jpg":"image/jpeg", - "js":"text/javascript", - "json":"application/json", - "latex":"application/x-latex", - "lsp":"application/x-lisp", - "lzh":"application/octet-stream", - "m":"text/plain", - "m3u":"audio/x-mpegurl", - "m4v":"video/mp4", - "man":"application/x-troff-man", - "me":"application/x-troff-me", - "midi":"audio/midi", - "mif":"application/x-mif", - "mime":"www/mime", - "mkv":" video/x-matrosk", - "movie":"video/x-sgi-movie", - "mp4":"video/mp4", - "mp41":"video/mp4", - "mp42":"video/mp4", - "mpg":"video/mpeg", - "mpga":"audio/mpeg", - "ms":"application/x-troff-ms", - "mustache":"text/plain", - "nc":"application/x-netcdf", - "oda":"application/oda", - "ogm":"application/ogg", - "pbm":"image/x-portable-bitmap", - "pdf":"application/pdf", - "pgm":"image/x-portable-graymap", - "pgn":"application/x-chess-pgn", - "pgp":"application/pgp", - "pm":"application/x-perl", - "png":"image/png", - "pnm":"image/x-portable-anymap", - "ppm":"image/x-portable-pixmap", - "ppz":"application/vnd.ms-powerpoint", - "pre":"application/x-freelance", - "prt":"application/pro_eng", - "ps":"application/postscript", - "qt":"video/quicktime", - "ra":"audio/x-realaudio", - "rar":"application/x-rar-compressed", - "ras":"image/x-cmu-raster", - "rgb":"image/x-rgb", - "rm":"audio/x-pn-realaudio", - "rpm":"audio/x-pn-realaudio-plugin", - "rtf":"text/rtf", - "rtx":"text/richtext", - "scm":"application/x-lotusscreencam", - "set":"application/set", - "sgml":"text/sgml", - "sh":"application/x-sh", - "shar":"application/x-shar", - "silo":"model/mesh", - "sit":"application/x-stuffit", - "skt":"application/x-koan", - "smil":"application/smil", - "snd":"audio/basic", - "sol":"application/solids", - "spl":"application/x-futuresplash", - "src":"application/x-wais-source", - "stl":"application/SLA", - "stp":"application/STEP", - "sv4cpio":"application/x-sv4cpio", - "sv4crc":"application/x-sv4crc", - "svg":"image/svg+xml", - "swf":"application/x-shockwave-flash", - "tar":"application/x-tar", - "tcl":"application/x-tcl", - "tex":"application/x-tex", - "texinfo":"application/x-texinfo", - "tgz":"application/x-tar-gz", - "tiff":"image/tiff", - "tr":"application/x-troff", - "tsi":"audio/TSP-audio", - "tsp":"application/dsptype", - "tsv":"text/tab-separated-values", - "unv":"application/i-deas", - "ustar":"application/x-ustar", - "vcd":"application/x-cdlink", - "vda":"application/vda", - "vivo":"video/vnd.vivo", - "vrm":"x-world/x-vrml", - "wav":"audio/x-wav", - "wax":"audio/x-ms-wax", - "webm":"video/webm", - "wma":"audio/x-ms-wma", - "wmv":"video/x-ms-wmv", - "wmx":"video/x-ms-wmx", - "wrl":"model/vrml", - "wvx":"video/x-ms-wvx", - "xbm":"image/x-xbitmap", - "xlw":"application/vnd.ms-excel", - "xml":"text/xml", - "xpm":"image/x-xpixmap", - "xwd":"image/x-xwindowdump", - "xyz":"chemical/x-pdb", - "zip":"application/zip" -}; - -exports.lookup = function(ext, defaultType) { - defaultType = defaultType || 'application/octet-stream'; - - return (ext in exports.types) - ? exports.types[ext] - : defaultType; -};
\ No newline at end of file diff --git a/node_modules/request/aws.js b/node_modules/request/node_modules/aws-sign/index.js index 4e87bff49..d3c705c06 100644 --- a/node_modules/request/aws.js +++ b/node_modules/request/node_modules/aws-sign/index.js @@ -10,14 +10,15 @@ */ var crypto = require('crypto') - , parse = require('url').parse; + , parse = require('url').parse + ; /** * Valid keys. */ -var keys = [ - 'acl' +var keys = + [ 'acl' , 'location' , 'logging' , 'notification' @@ -31,7 +32,7 @@ var keys = [ , 'versioning' , 'versions' , 'website' -]; + ] /** * Return an "Authorization" header value with the given `options` @@ -42,9 +43,12 @@ var keys = [ * @api private */ -exports.authorization = function(options){ - return 'AWS ' + options.key + ':' + exports.sign(options); -}; +function authorization (options) { + return 'AWS ' + options.key + ':' + sign(options) +} + +module.exports = authorization +module.exports.authorization = authorization /** * Simple HMAC-SHA1 Wrapper @@ -54,9 +58,11 @@ exports.authorization = function(options){ * @api private */ -exports.hmacSha1 = function(options){ - return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64'); -}; +function hmacSha1 (options) { + return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64') +} + +module.exports.hmacSha1 = hmacSha1 /** * Create a base64 sha1 HMAC for `options`. @@ -66,10 +72,11 @@ exports.hmacSha1 = function(options){ * @api private */ -exports.sign = function(options){ - options.message = exports.stringToSign(options); - return exports.hmacSha1(options); -}; +function sign (options) { + options.message = stringToSign(options) + return hmacSha1(options) +} +module.exports.sign = sign /** * Create a base64 sha1 HMAC for `options`. @@ -81,10 +88,11 @@ exports.sign = function(options){ * @api private */ -exports.signQuery = function(options){ - options.message = exports.queryStringToSign(options); - return exports.hmacSha1(options); -}; +function signQuery (options) { + options.message = queryStringToSign(options) + return hmacSha1(options) +} +module.exports.signQuery= signQuery /** * Return a string for sign() with the given `options`. @@ -103,17 +111,19 @@ exports.signQuery = function(options){ * @api private */ -exports.stringToSign = function(options){ - var headers = options.amazonHeaders || ''; - if (headers) headers += '\n'; - return [ - options.verb +function stringToSign (options) { + var headers = options.amazonHeaders || '' + if (headers) headers += '\n' + var r = + [ options.verb , options.md5 , options.contentType , options.date.toUTCString() , headers + options.resource - ].join('\n'); -}; + ] + return r.join('\n') +} +module.exports.queryStringToSign = stringToSign /** * Return a string for sign() with the given `options`, but is meant exclusively @@ -129,11 +139,10 @@ exports.stringToSign = function(options){ * @api private */ -exports.queryStringToSign = function(options){ - return 'GET\n\n\n' + - options.date + '\n' + - options.resource; -}; +function queryStringToSign (options){ + return 'GET\n\n\n' + options.date + '\n' + options.resource +} +module.exports.queryStringToSign = queryStringToSign /** * Perform the following: @@ -149,18 +158,21 @@ exports.queryStringToSign = function(options){ * @api private */ -exports.canonicalizeHeaders = function(headers){ +function canonicalizeHeaders (headers) { var buf = [] - , fields = Object.keys(headers); + , fields = Object.keys(headers) + ; for (var i = 0, len = fields.length; i < len; ++i) { var field = fields[i] , val = headers[field] - , field = field.toLowerCase(); - if (0 !== field.indexOf('x-amz')) continue; - buf.push(field + ':' + val); + , field = field.toLowerCase() + ; + if (0 !== field.indexOf('x-amz')) continue + buf.push(field + ':' + val) } - return buf.sort().join('\n'); -}; + return buf.sort().join('\n') +} +module.exports.canonicalizeHeaders = canonicalizeHeaders /** * Perform the following: @@ -173,18 +185,18 @@ exports.canonicalizeHeaders = function(headers){ * @api private */ -exports.canonicalizeResource = function(resource){ +function canonicalizeResource (resource) { var url = parse(resource, true) , path = url.pathname - , buf = []; + , buf = [] + ; Object.keys(url.query).forEach(function(key){ - if (!~keys.indexOf(key)) return; - var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]); - buf.push(key + val); - }); - - return path + (buf.length - ? '?' + buf.sort().join('&') - : ''); -}; + if (!~keys.indexOf(key)) return + var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]) + buf.push(key + val) + }) + + return path + (buf.length ? '?' + buf.sort().join('&') : '') +} +module.exports.canonicalizeResource = canonicalizeResource diff --git a/node_modules/request/node_modules/aws-sign/package.json b/node_modules/request/node_modules/aws-sign/package.json new file mode 100644 index 000000000..8d8b1c7de --- /dev/null +++ b/node_modules/request/node_modules/aws-sign/package.json @@ -0,0 +1,27 @@ +{ + "author": { + "name": "Mikeal Rogers", + "email": "mikeal.rogers@gmail.com", + "url": "http://www.futurealoof.com" + }, + "name": "aws-sign", + "description": "AWS signing. Originally pulled from LearnBoost/knox, maintained as vendor in request, now a standalone module.", + "version": "0.2.0", + "repository": { + "url": "https://github.com/mikeal/aws-sign" + }, + "main": "index.js", + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "_id": "aws-sign@0.2.0", + "readme": "ERROR: No README.md file found!", + "dist": { + "shasum": "46d6af187cc38dffdb83670acd860bcd220c74eb" + }, + "_from": "aws-sign@~0.2.0", + "_resolved": "https://registry.npmjs.org/aws-sign/-/aws-sign-0.2.0.tgz" +} diff --git a/node_modules/request/vendor/cookie/index.js b/node_modules/request/node_modules/cookie-jar/index.js index ff44b3e62..7d54d940c 100644 --- a/node_modules/request/vendor/cookie/index.js +++ b/node_modules/request/node_modules/cookie-jar/index.js @@ -63,3 +63,5 @@ var Cookie = exports = module.exports = function Cookie(str, req) { Cookie.prototype.toString = function(){ return this.str; }; + +module.exports.Jar = require('./jar')
\ No newline at end of file diff --git a/node_modules/request/vendor/cookie/jar.js b/node_modules/request/node_modules/cookie-jar/jar.js index 34920e062..34920e062 100644 --- a/node_modules/request/vendor/cookie/jar.js +++ b/node_modules/request/node_modules/cookie-jar/jar.js diff --git a/node_modules/request/node_modules/cookie-jar/package.json b/node_modules/request/node_modules/cookie-jar/package.json new file mode 100644 index 000000000..ff171db69 --- /dev/null +++ b/node_modules/request/node_modules/cookie-jar/package.json @@ -0,0 +1,30 @@ +{ + "author": { + "name": "Mikeal Rogers", + "email": "mikeal.rogers@gmail.com", + "url": "http://www.futurealoof.com" + }, + "name": "cookie-jar", + "description": "Cookie Jar. Originally pulled form tobi, maintained as vendor in request, now a standalone module.", + "version": "0.2.0", + "repository": { + "url": "https://github.com/mikeal/cookie-jar" + }, + "main": "index.js", + "scripts": { + "test": "node tests/run.js" + }, + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "_id": "cookie-jar@0.2.0", + "readme": "ERROR: No README.md file found!", + "dist": { + "shasum": "081cfd8f8ff4b8a93c7fc12e8d0fc5218e1e45a3" + }, + "_from": "cookie-jar@~0.2.0", + "_resolved": "https://registry.npmjs.org/cookie-jar/-/cookie-jar-0.2.0.tgz" +} diff --git a/node_modules/request/node_modules/cookie-jar/tests/run.js b/node_modules/request/node_modules/cookie-jar/tests/run.js new file mode 100644 index 000000000..e717f02a3 --- /dev/null +++ b/node_modules/request/node_modules/cookie-jar/tests/run.js @@ -0,0 +1,40 @@ +var spawn = require('child_process').spawn + , exitCode = 0 + , timeout = 10000 + , fs = require('fs') + ; + +fs.readdir(__dirname, function (e, files) { + if (e) throw e + + var tests = files.filter(function (f) {return f.slice(0, 'test-'.length) === 'test-'}) + + var next = function () { + if (tests.length === 0) process.exit(exitCode); + + var file = tests.shift() + console.log(file) + var proc = spawn('node', [ 'tests/' + file ]) + + var killed = false + var t = setTimeout(function () { + proc.kill() + exitCode += 1 + console.error(file + ' timeout') + killed = true + }, timeout) + + proc.stdout.pipe(process.stdout) + proc.stderr.pipe(process.stderr) + proc.on('exit', function (code) { + if (code && !killed) console.error(file + ' failed') + exitCode += code || 0 + clearTimeout(t) + next() + }) + } + next() + +}) + + diff --git a/node_modules/request/tests/test-cookie.js b/node_modules/request/node_modules/cookie-jar/tests/test-cookie.js index 6c6a7a779..2cdc835bb 100644 --- a/node_modules/request/tests/test-cookie.js +++ b/node_modules/request/node_modules/cookie-jar/tests/test-cookie.js @@ -1,4 +1,4 @@ -var Cookie = require('../vendor/cookie') +var Cookie = require('../index') , assert = require('assert'); var str = 'Sid="s543qactge.wKE61E01Bs%2BKhzmxrwrnug="; Path=/; httpOnly; Expires=Sat, 04 Dec 2010 23:27:28 GMT'; diff --git a/node_modules/request/tests/test-cookiejar.js b/node_modules/request/node_modules/cookie-jar/tests/test-cookiejar.js index 76fcd7161..a33cfb232 100644 --- a/node_modules/request/tests/test-cookiejar.js +++ b/node_modules/request/node_modules/cookie-jar/tests/test-cookiejar.js @@ -1,5 +1,5 @@ -var Cookie = require('../vendor/cookie') - , Jar = require('../vendor/cookie/jar') +var Cookie = require('../index') + , Jar = Cookie.Jar , assert = require('assert'); function expires(ms) { diff --git a/node_modules/request/forever.js b/node_modules/request/node_modules/forever-agent/index.js index ac853c0d2..1e1d4b9cf 100644 --- a/node_modules/request/forever.js +++ b/node_modules/request/node_modules/forever-agent/index.js @@ -34,7 +34,7 @@ function ForeverAgent(options) { // socket and it will get removed from the pool. This // gets us out of timeout issues and allows us to // default to Connection:keep-alive. - socket.destroy(); + socket.destroy() } }) @@ -61,14 +61,14 @@ ForeverAgent.prototype.addRequest = function(req, host, port) { ForeverAgent.prototype.removeSocket = function(s, name, host, port) { if (this.sockets[name]) { - var index = this.sockets[name].indexOf(s); + var index = this.sockets[name].indexOf(s) if (index !== -1) { - this.sockets[name].splice(index, 1); + this.sockets[name].splice(index, 1) } } else if (this.sockets[name] && this.sockets[name].length === 0) { // don't leak - delete this.sockets[name]; - delete this.requests[name]; + delete this.sockets[name] + delete this.requests[name] } if (this.freeSockets[name]) { @@ -84,7 +84,7 @@ ForeverAgent.prototype.removeSocket = function(s, name, host, port) { if (this.requests[name] && this.requests[name].length) { // If we have pending requests and a socket gets closed a new one // needs to be created to take over in the pool for the one that closed. - this.createSocket(name, host, port).emit('free'); + this.createSocket(name, host, port).emit('free') } } diff --git a/node_modules/request/node_modules/forever-agent/package.json b/node_modules/request/node_modules/forever-agent/package.json new file mode 100644 index 000000000..4a8c570ea --- /dev/null +++ b/node_modules/request/node_modules/forever-agent/package.json @@ -0,0 +1,27 @@ +{ + "author": { + "name": "Mikeal Rogers", + "email": "mikeal.rogers@gmail.com", + "url": "http://www.futurealoof.com" + }, + "name": "forever-agent", + "description": "HTTP Agent that keeps socket connections alive between keep-alive requests. Formerly part of mikeal/request, now a standalone module.", + "version": "0.2.0", + "repository": { + "url": "https://github.com/mikeal/forever-agent" + }, + "main": "index.js", + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "_id": "forever-agent@0.2.0", + "readme": "ERROR: No README.md file found!", + "dist": { + "shasum": "5dc7762818ad15c3cac9d9f99aceedbee15734be" + }, + "_from": "forever-agent@~0.2.0", + "_resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.2.0.tgz" +} diff --git a/node_modules/request/node_modules/form-data/.npmignore b/node_modules/request/node_modules/form-data/.npmignore new file mode 100644 index 000000000..85957343e --- /dev/null +++ b/node_modules/request/node_modules/form-data/.npmignore @@ -0,0 +1,5 @@ +*.un~ +/node_modules/* +/test/tmp +/.idea +*.iml diff --git a/node_modules/request/node_modules/form-data/License b/node_modules/request/node_modules/form-data/License new file mode 100644 index 000000000..c7ff12a2f --- /dev/null +++ b/node_modules/request/node_modules/form-data/License @@ -0,0 +1,19 @@ +Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/node_modules/request/node_modules/form-data/Makefile b/node_modules/request/node_modules/form-data/Makefile new file mode 100644 index 000000000..b4ff85a33 --- /dev/null +++ b/node_modules/request/node_modules/form-data/Makefile @@ -0,0 +1,7 @@ +SHELL := /bin/bash + +test: + @./test/run.js + +.PHONY: test + diff --git a/node_modules/request/node_modules/form-data/Readme.md b/node_modules/request/node_modules/form-data/Readme.md new file mode 100644 index 000000000..fe9d8bbff --- /dev/null +++ b/node_modules/request/node_modules/form-data/Readme.md @@ -0,0 +1,118 @@ +# form-data + +A module to create readable `"multipart/form-data"` streams. Can be used to +submit forms and file uploads to other web applications. + +The API of this module is inspired by the +[XMLHttpRequest-2 FormData Interface][xhr2-fd]. + +[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface + +## Install + +Sorry, this isn't ready for you yet. + +## Usage + +In this example we are constructing a form with 3 fields that contain a string, +a buffer and a file stream. + +``` javascript +var FormData = require('form-data'); +var fs = require('fs'); + +var form = new FormData(); +form.append('my_field', 'my value'); +form.append('my_buffer', new Buffer(10)); +form.append('my_file', fs.createReadStream('/foo/bar.jpg')); +``` + +Also you can use http-response stream: + +``` javascript +var FormData = require('form-data'); +var http = require('http'); + +var form = new FormData(); + +http.request('http://nodejs.org/images/logo.png', function(response) { + form.append('my_field', 'my value'); + form.append('my_buffer', new Buffer(10)); + form.append('my_logo', response); +}); +``` + +Or @mikeal's request stream: + +``` javascript +var FormData = require('form-data'); +var request = require('request'); + +var form = new FormData(); + +form.append('my_field', 'my value'); +form.append('my_buffer', new Buffer(10)); +form.append('my_logo', request('http://nodejs.org/images/logo.png')); +``` + +In order to submit this form to a web application, you can use node's http +client interface: + +``` javascript +var http = require('http'); + +var request = http.request({ + method: 'post', + host: 'example.org', + path: '/upload', + headers: form.getHeaders() +}); + +form.pipe(request); + +request.on('response', function(res) { + console.log(res.statusCode); +}); +``` + +Or if you would prefer the `'Content-Length'` header to be set for you: + +``` javascript +form.submit('example.org/upload', function(err, res) { + console.log(res.statusCode); +}); +``` + +To use custom headers and pre-known length in parts: + +``` javascript +var CRLF = '\r\n'; +var form = new FormData(); + +var options = { + header: CRLF + '--' + form.getBoundary() + CRLF + 'X-Custom-Header: 123' + CRLF + CRLF, + knownLength: 1 +}; + +form.append('my_buffer', buffer, options); + +form.submit('http://example.com/', function(err, res) { + if (err) throw err; + console.log('Done'); +}); +``` + +For edge cases, like POST request to URL with query string or to pass HTTP auth creadentials, object can be passed to `form.submit()` as first parameter: + +``` javascript +form.submit({ + host: 'example.com', + path: '/probably.php?extra=params', + auth: 'username:password' +}, function(err, res) { + console.log(res.statusCode); +}); +``` + + +[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface diff --git a/node_modules/request/node_modules/form-data/lib/form_data.js b/node_modules/request/node_modules/form-data/lib/form_data.js new file mode 100644 index 000000000..f61528887 --- /dev/null +++ b/node_modules/request/node_modules/form-data/lib/form_data.js @@ -0,0 +1,291 @@ +var CombinedStream = require('combined-stream'); +var util = require('util'); +var path = require('path'); +var http = require('http'); +var https = require('https'); +var parseUrl = require('url').parse; +var fs = require('fs'); +var mime = require('mime'); +var async = require('async'); + +module.exports = FormData; +function FormData() { + this._overheadLength = 0; + this._valueLength = 0; + this._lengthRetrievers = []; + + CombinedStream.call(this); +} +util.inherits(FormData, CombinedStream); + +FormData.LINE_BREAK = '\r\n'; + +FormData.prototype.append = function(field, value, options) { + options = options || {}; + + var append = CombinedStream.prototype.append.bind(this); + + // all that streamy business can't handle numbers + if (typeof value == 'number') value = ''+value; + + var header = this._multiPartHeader(field, value, options); + var footer = this._multiPartFooter(field, value, options); + + append(header); + append(value); + append(footer); + + // pass along options.knownLength + this._trackLength(header, value, options); +}; + +FormData.prototype._trackLength = function(header, value, options) { + var valueLength = 0; + + // used w/ trackLengthSync(), when length is known. + // e.g. for streaming directly from a remote server, + // w/ a known file a size, and not wanting to wait for + // incoming file to finish to get its size. + if (options.knownLength != null) { + valueLength += +options.knownLength; + } else if (Buffer.isBuffer(value)) { + valueLength = value.length; + } else if (typeof value === 'string') { + valueLength = Buffer.byteLength(value); + } + + this._valueLength += valueLength; + + // @check why add CRLF? does this account for custom/multiple CRLFs? + this._overheadLength += + Buffer.byteLength(header) + + + FormData.LINE_BREAK.length; + + // empty or either doesn't have path or not an http response + if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) )) { + return; + } + + this._lengthRetrievers.push(function(next) { + + // do we already know the size? + // 0 additional leaves value from getSyncLength() + if (options.knownLength != null) { + next(null, 0); + + // check if it's local file + } else if (value.hasOwnProperty('fd')) { + fs.stat(value.path, function(err, stat) { + if (err) { + next(err); + return; + } + + next(null, stat.size); + }); + + // or http response + } else if (value.hasOwnProperty('httpVersion')) { + next(null, +value.headers['content-length']); + + // or request stream http://github.com/mikeal/request + } else if (value.hasOwnProperty('httpModule')) { + // wait till response come back + value.on('response', function(response) { + value.pause(); + next(null, +response.headers['content-length']); + }); + value.resume(); + + // something else + } else { + next('Unknown stream'); + } + }); +}; + +FormData.prototype._multiPartHeader = function(field, value, options) { + var boundary = this.getBoundary(); + var header = ''; + + // custom header specified (as string)? + // it becomes responsible for boundary + // (e.g. to handle extra CRLFs on .NET servers) + if (options.header != null) { + header = options.header; + } else { + header += '--' + boundary + FormData.LINE_BREAK + + 'Content-Disposition: form-data; name="' + field + '"'; + + // fs- and request- streams have path property + // TODO: Use request's response mime-type + if (value.path) { + header += + '; filename="' + path.basename(value.path) + '"' + FormData.LINE_BREAK + + 'Content-Type: ' + mime.lookup(value.path); + + // http response has not + } else if (value.readable && value.hasOwnProperty('httpVersion')) { + header += + '; filename="' + path.basename(value.client._httpMessage.path) + '"' + FormData.LINE_BREAK + + 'Content-Type: ' + value.headers['content-type']; + } + + header += FormData.LINE_BREAK + FormData.LINE_BREAK; + } + + return header; +}; + +FormData.prototype._multiPartFooter = function(field, value, options) { + return function(next) { + var footer = FormData.LINE_BREAK; + + var lastPart = (this._streams.length === 0); + if (lastPart) { + footer += this._lastBoundary(); + } + + next(footer); + }.bind(this); +}; + +FormData.prototype._lastBoundary = function() { + return '--' + this.getBoundary() + '--'; +}; + +FormData.prototype.getHeaders = function(userHeaders) { + var formHeaders = { + 'content-type': 'multipart/form-data; boundary=' + this.getBoundary() + }; + + for (var header in userHeaders) { + formHeaders[header.toLowerCase()] = userHeaders[header]; + } + + return formHeaders; +} + +FormData.prototype.getCustomHeaders = function(contentType) { + contentType = contentType ? contentType : 'multipart/form-data'; + + var formHeaders = { + 'content-type': contentType + '; boundary=' + this.getBoundary(), + 'content-length': this.getLengthSync() + }; + + return formHeaders; +} + +FormData.prototype.getBoundary = function() { + if (!this._boundary) { + this._generateBoundary(); + } + + return this._boundary; +}; + +FormData.prototype._generateBoundary = function() { + // This generates a 50 character boundary similar to those used by Firefox. + // They are optimized for boyer-moore parsing. + var boundary = '--------------------------'; + for (var i = 0; i < 24; i++) { + boundary += Math.floor(Math.random() * 10).toString(16); + } + + this._boundary = boundary; +}; + +FormData.prototype.getLengthSync = function() { + var knownLength = this._overheadLength + this._valueLength; + + if (this._streams.length) { + knownLength += this._lastBoundary().length; + } + + return knownLength; +}; + +FormData.prototype.getLength = function(cb) { + var knownLength = this._overheadLength + this._valueLength; + + if (this._streams.length) { + knownLength += this._lastBoundary().length; + } + + if (!this._lengthRetrievers.length) { + process.nextTick(cb.bind(this, null, knownLength)); + return; + } + + async.parallel(this._lengthRetrievers, function(err, values) { + if (err) { + cb(err); + return; + } + + values.forEach(function(length) { + knownLength += length; + }); + + cb(null, knownLength); + }); +}; + +FormData.prototype.submit = function(params, cb) { + this.getLength(function(err, length) { + + var request + , options + , defaults = { + method : 'post', + port : 80, + headers: this.getHeaders({'Content-Length': length}) + }; + + // parse provided url if it's string + // or treat it as options object + if (typeof params == 'string') { + params = parseUrl(params); + + options = populate({ + port: params.port, + path: params.pathname, + host: params.hostname + }, defaults); + } + else // use custom params + { + options = populate(params, defaults); + } + + // https if specified, fallback to http in any other case + if (params.protocol == 'https:') { + // override default port + if (!params.port) options.port = 443; + request = https.request(options); + } else { + request = http.request(options); + } + + this.pipe(request); + if (cb) { + request.on('error', cb); + request.on('response', cb.bind(this, null)); + } + + return request; + }.bind(this)); +}; + +/* + * Santa's little helpers + */ + +// populates missing values +function populate(dst, src) { + for (var prop in src) { + if (!dst[prop]) dst[prop] = src[prop]; + } + return dst; +} diff --git a/node_modules/request/node_modules/form-data/node_modules/async/.gitmodules b/node_modules/request/node_modules/form-data/node_modules/async/.gitmodules new file mode 100644 index 000000000..a9aae984f --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/async/.gitmodules @@ -0,0 +1,9 @@ +[submodule "deps/nodeunit"] + path = deps/nodeunit + url = git://github.com/caolan/nodeunit.git +[submodule "deps/UglifyJS"] + path = deps/UglifyJS + url = https://github.com/mishoo/UglifyJS.git +[submodule "deps/nodelint"] + path = deps/nodelint + url = https://github.com/tav/nodelint.git diff --git a/node_modules/request/node_modules/form-data/node_modules/async/.npmignore b/node_modules/request/node_modules/form-data/node_modules/async/.npmignore new file mode 100644 index 000000000..9bdfc97ca --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/async/.npmignore @@ -0,0 +1,4 @@ +deps +dist +test +nodelint.cfg
\ No newline at end of file diff --git a/node_modules/request/node_modules/form-data/node_modules/async/LICENSE b/node_modules/request/node_modules/form-data/node_modules/async/LICENSE new file mode 100644 index 000000000..b7f9d5001 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/async/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Caolan McMahon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/request/node_modules/form-data/node_modules/async/Makefile b/node_modules/request/node_modules/form-data/node_modules/async/Makefile new file mode 100644 index 000000000..bad647c63 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/async/Makefile @@ -0,0 +1,25 @@ +PACKAGE = asyncjs +NODEJS = $(if $(shell test -f /usr/bin/nodejs && echo "true"),nodejs,node) +CWD := $(shell pwd) +NODEUNIT = $(CWD)/node_modules/nodeunit/bin/nodeunit +UGLIFY = $(CWD)/node_modules/uglify-js/bin/uglifyjs +NODELINT = $(CWD)/node_modules/nodelint/nodelint + +BUILDDIR = dist + +all: clean test build + +build: $(wildcard lib/*.js) + mkdir -p $(BUILDDIR) + $(UGLIFY) lib/async.js > $(BUILDDIR)/async.min.js + +test: + $(NODEUNIT) test + +clean: + rm -rf $(BUILDDIR) + +lint: + $(NODELINT) --config nodelint.cfg lib/async.js + +.PHONY: test build all diff --git a/node_modules/request/node_modules/form-data/node_modules/async/README.md b/node_modules/request/node_modules/form-data/node_modules/async/README.md new file mode 100644 index 000000000..1bbbc477e --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/async/README.md @@ -0,0 +1,1021 @@ +# Async.js + +Async is a utility module which provides straight-forward, powerful functions +for working with asynchronous JavaScript. Although originally designed for +use with [node.js](http://nodejs.org), it can also be used directly in the +browser. + +Async provides around 20 functions that include the usual 'functional' +suspects (map, reduce, filter, forEach…) as well as some common patterns +for asynchronous control flow (parallel, series, waterfall…). All these +functions assume you follow the node.js convention of providing a single +callback as the last argument of your async function. + + +## Quick Examples + + async.map(['file1','file2','file3'], fs.stat, function(err, results){ + // results is now an array of stats for each file + }); + + async.filter(['file1','file2','file3'], path.exists, function(results){ + // results now equals an array of the existing files + }); + + async.parallel([ + function(){ ... }, + function(){ ... } + ], callback); + + async.series([ + function(){ ... }, + function(){ ... } + ]); + +There are many more functions available so take a look at the docs below for a +full list. This module aims to be comprehensive, so if you feel anything is +missing please create a GitHub issue for it. + + +## Download + +Releases are available for download from +[GitHub](http://github.com/caolan/async/downloads). +Alternatively, you can install using Node Package Manager (npm): + + npm install async + + +__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 17.5kb Uncompressed + +__Production:__ [async.min.js](https://github.com/caolan/async/raw/master/dist/async.min.js) - 1.7kb Packed and Gzipped + + +## In the Browser + +So far its been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage: + + <script type="text/javascript" src="async.js"></script> + <script type="text/javascript"> + + async.map(data, asyncProcess, function(err, results){ + alert(results); + }); + + </script> + + +## Documentation + +### Collections + +* [forEach](#forEach) +* [map](#map) +* [filter](#filter) +* [reject](#reject) +* [reduce](#reduce) +* [detect](#detect) +* [sortBy](#sortBy) +* [some](#some) +* [every](#every) +* [concat](#concat) + +### Control Flow + +* [series](#series) +* [parallel](#parallel) +* [whilst](#whilst) +* [until](#until) +* [waterfall](#waterfall) +* [queue](#queue) +* [auto](#auto) +* [iterator](#iterator) +* [apply](#apply) +* [nextTick](#nextTick) + +### Utils + +* [memoize](#memoize) +* [unmemoize](#unmemoize) +* [log](#log) +* [dir](#dir) +* [noConflict](#noConflict) + + +## Collections + +<a name="forEach" /> +### forEach(arr, iterator, callback) + +Applies an iterator function to each item in an array, in parallel. +The iterator is called with an item from the list and a callback for when it +has finished. If the iterator passes an error to this callback, the main +callback for the forEach function is immediately called with the error. + +Note, that since this function applies the iterator to each item in parallel +there is no guarantee that the iterator functions will complete in order. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(err) - A callback which is called after all the iterator functions + have finished, or an error has occurred. + +__Example__ + + // assuming openFiles is an array of file names and saveFile is a function + // to save the modified contents of that file: + + async.forEach(openFiles, saveFile, function(err){ + // if any of the saves produced an error, err would equal that error + }); + +--------------------------------------- + +<a name="forEachSeries" /> +### forEachSeries(arr, iterator, callback) + +The same as forEach only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. This means the iterator functions will complete in order. + + +--------------------------------------- + +<a name="forEachLimit" /> +### forEachLimit(arr, limit, iterator, callback) + +The same as forEach only the iterator is applied to batches of items in the +array, in series. The next batch of iterators is only called once the current +one has completed processing. + +__Arguments__ + +* arr - An array to iterate over. +* limit - How many items should be in each batch. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(err) - A callback which is called after all the iterator functions + have finished, or an error has occurred. + +__Example__ + + // Assume documents is an array of JSON objects and requestApi is a + // function that interacts with a rate-limited REST api. + + async.forEachLimit(documents, 20, requestApi, function(err){ + // if any of the saves produced an error, err would equal that error + }); +--------------------------------------- + +<a name="map" /> +### map(arr, iterator, callback) + +Produces a new array of values by mapping each value in the given array through +the iterator function. The iterator is called with an item from the array and a +callback for when it has finished processing. The callback takes 2 arguments, +an error and the transformed item from the array. If the iterator passes an +error to this callback, the main callback for the map function is immediately +called with the error. + +Note, that since this function applies the iterator to each item in parallel +there is no guarantee that the iterator functions will complete in order, however +the results array will be in the same order as the original array. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed + with an error (which can be null) and a transformed item. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array of the + transformed items from the original array. + +__Example__ + + async.map(['file1','file2','file3'], fs.stat, function(err, results){ + // results is now an array of stats for each file + }); + +--------------------------------------- + +<a name="mapSeries" /> +### mapSeries(arr, iterator, callback) + +The same as map only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + + +--------------------------------------- + +<a name="filter" /> +### filter(arr, iterator, callback) + +__Alias:__ select + +Returns a new array of all the values which pass an async truth test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like path.exists. This operation is +performed in parallel, but the results array will be in the same order as the +original. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(results) - A callback which is called after all the iterator + functions have finished. + +__Example__ + + async.filter(['file1','file2','file3'], path.exists, function(results){ + // results now equals an array of the existing files + }); + +--------------------------------------- + +<a name="filterSeries" /> +### filterSeries(arr, iterator, callback) + +__alias:__ selectSeries + +The same as filter only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + +--------------------------------------- + +<a name="reject" /> +### reject(arr, iterator, callback) + +The opposite of filter. Removes values that pass an async truth test. + +--------------------------------------- + +<a name="rejectSeries" /> +### rejectSeries(arr, iterator, callback) + +The same as filter, only the iterator is applied to each item in the array +in series. + + +--------------------------------------- + +<a name="reduce" /> +### reduce(arr, memo, iterator, callback) + +__aliases:__ inject, foldl + +Reduces a list of values into a single value using an async iterator to return +each successive step. Memo is the initial state of the reduction. This +function only operates in series. For performance reasons, it may make sense to +split a call to this function into a parallel map, then use the normal +Array.prototype.reduce on the results. This function is for situations where +each step in the reduction needs to be async, if you can get the data before +reducing it then its probably a good idea to do so. + +__Arguments__ + +* arr - An array to iterate over. +* memo - The initial state of the reduction. +* iterator(memo, item, callback) - A function applied to each item in the + array to produce the next step in the reduction. The iterator is passed a + callback which accepts an optional error as its first argument, and the state + of the reduction as the second. If an error is passed to the callback, the + reduction is stopped and the main callback is immediately called with the + error. +* callback(err, result) - A callback which is called after all the iterator + functions have finished. Result is the reduced value. + +__Example__ + + async.reduce([1,2,3], 0, function(memo, item, callback){ + // pointless async: + process.nextTick(function(){ + callback(null, memo + item) + }); + }, function(err, result){ + // result is now equal to the last value of memo, which is 6 + }); + +--------------------------------------- + +<a name="reduceRight" /> +### reduceRight(arr, memo, iterator, callback) + +__Alias:__ foldr + +Same as reduce, only operates on the items in the array in reverse order. + + +--------------------------------------- + +<a name="detect" /> +### detect(arr, iterator, callback) + +Returns the first value in a list that passes an async truth test. The +iterator is applied in parallel, meaning the first iterator to return true will +fire the detect callback with that result. That means the result might not be +the first item in the original array (in terms of order) that passes the test. + +If order within the original array is important then look at detectSeries. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(result) - A callback which is called as soon as any iterator returns + true, or after all the iterator functions have finished. Result will be + the first item in the array that passes the truth test (iterator) or the + value undefined if none passed. + +__Example__ + + async.detect(['file1','file2','file3'], path.exists, function(result){ + // result now equals the first file in the list that exists + }); + +--------------------------------------- + +<a name="detectSeries" /> +### detectSeries(arr, iterator, callback) + +The same as detect, only the iterator is applied to each item in the array +in series. This means the result is always the first in the original array (in +terms of array order) that passes the truth test. + + +--------------------------------------- + +<a name="sortBy" /> +### sortBy(arr, iterator, callback) + +Sorts a list by the results of running each value through an async iterator. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed + with an error (which can be null) and a value to use as the sort criteria. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is the items from + the original array sorted by the values returned by the iterator calls. + +__Example__ + + async.sortBy(['file1','file2','file3'], function(file, callback){ + fs.stat(file, function(err, stats){ + callback(err, stats.mtime); + }); + }, function(err, results){ + // results is now the original array of files sorted by + // modified date + }); + + +--------------------------------------- + +<a name="some" /> +### some(arr, iterator, callback) + +__Alias:__ any + +Returns true if at least one element in the array satisfies an async test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like path.exists. Once any iterator +call returns true, the main callback is immediately called. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(result) - A callback which is called as soon as any iterator returns + true, or after all the iterator functions have finished. Result will be + either true or false depending on the values of the async tests. + +__Example__ + + async.some(['file1','file2','file3'], path.exists, function(result){ + // if result is true then at least one of the files exists + }); + +--------------------------------------- + +<a name="every" /> +### every(arr, iterator, callback) + +__Alias:__ all + +Returns true if every element in the array satisfies an async test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like path.exists. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed. +* callback(result) - A callback which is called after all the iterator + functions have finished. Result will be either true or false depending on + the values of the async tests. + +__Example__ + + async.every(['file1','file2','file3'], path.exists, function(result){ + // if result is true then every file exists + }); + +--------------------------------------- + +<a name="concat" /> +### concat(arr, iterator, callback) + +Applies an iterator to each item in a list, concatenating the results. Returns the +concatenated list. The iterators are called in parallel, and the results are +concatenated as they return. There is no guarantee that the results array will +be returned in the original order of the arguments passed to the iterator function. + +__Arguments__ + +* arr - An array to iterate over +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback which must be called once it has completed + with an error (which can be null) and an array of results. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array containing + the concatenated results of the iterator function. + +__Example__ + + async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){ + // files is now a list of filenames that exist in the 3 directories + }); + +--------------------------------------- + +<a name="concatSeries" /> +### concatSeries(arr, iterator, callback) + +Same as async.concat, but executes in series instead of parallel. + + +## Control Flow + +<a name="series" /> +### series(tasks, [callback]) + +Run an array of functions in series, each one running once the previous +function has completed. If any functions in the series pass an error to its +callback, no more functions are run and the callback for the series is +immediately called with the value of the error. Once the tasks have completed, +the results are passed to the final callback as an array. + +It is also possible to use an object instead of an array. Each property will be +run as a function and the results will be passed to the final callback as an object +instead of an array. This can be a more readable way of handling results from +async.series. + + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed + a callback it must call on completion. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets an array of all the arguments passed to + the callbacks used in the array. + +__Example__ + + async.series([ + function(callback){ + // do some stuff ... + callback(null, 'one'); + }, + function(callback){ + // do some more stuff ... + callback(null, 'two'); + }, + ], + // optional callback + function(err, results){ + // results is now equal to ['one', 'two'] + }); + + + // an example using an object instead of an array + async.series({ + one: function(callback){ + setTimeout(function(){ + callback(null, 1); + }, 200); + }, + two: function(callback){ + setTimeout(function(){ + callback(null, 2); + }, 100); + }, + }, + function(err, results) { + // results is now equal to: {one: 1, two: 2} + }); + + +--------------------------------------- + +<a name="parallel" /> +### parallel(tasks, [callback]) + +Run an array of functions in parallel, without waiting until the previous +function has completed. If any of the functions pass an error to its +callback, the main callback is immediately called with the value of the error. +Once the tasks have completed, the results are passed to the final callback as an +array. + +It is also possible to use an object instead of an array. Each property will be +run as a function and the results will be passed to the final callback as an object +instead of an array. This can be a more readable way of handling results from +async.parallel. + + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed a + callback it must call on completion. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets an array of all the arguments passed to + the callbacks used in the array. + +__Example__ + + async.parallel([ + function(callback){ + setTimeout(function(){ + callback(null, 'one'); + }, 200); + }, + function(callback){ + setTimeout(function(){ + callback(null, 'two'); + }, 100); + }, + ], + // optional callback + function(err, results){ + // the results array will equal ['one','two'] even though + // the second function had a shorter timeout. + }); + + + // an example using an object instead of an array + async.parallel({ + one: function(callback){ + setTimeout(function(){ + callback(null, 1); + }, 200); + }, + two: function(callback){ + setTimeout(function(){ + callback(null, 2); + }, 100); + }, + }, + function(err, results) { + // results is now equals to: {one: 1, two: 2} + }); + + +--------------------------------------- + +<a name="whilst" /> +### whilst(test, fn, callback) + +Repeatedly call fn, while test returns true. Calls the callback when stopped, +or an error occurs. + +__Arguments__ + +* test() - synchronous truth test to perform before each execution of fn. +* fn(callback) - A function to call each time the test passes. The function is + passed a callback which must be called once it has completed with an optional + error as the first argument. +* callback(err) - A callback which is called after the test fails and repeated + execution of fn has stopped. + +__Example__ + + var count = 0; + + async.whilst( + function () { return count < 5; }, + function (callback) { + count++; + setTimeout(callback, 1000); + }, + function (err) { + // 5 seconds have passed + } + ); + + +--------------------------------------- + +<a name="until" /> +### until(test, fn, callback) + +Repeatedly call fn, until test returns true. Calls the callback when stopped, +or an error occurs. + +The inverse of async.whilst. + + +--------------------------------------- + +<a name="waterfall" /> +### waterfall(tasks, [callback]) + +Runs an array of functions in series, each passing their results to the next in +the array. However, if any of the functions pass an error to the callback, the +next function is not executed and the main callback is immediately called with +the error. + +__Arguments__ + +* tasks - An array of functions to run, each function is passed a callback it + must call on completion. +* callback(err, [results]) - An optional callback to run once all the functions + have completed. This will be passed the results of the last task's callback. + + + +__Example__ + + async.waterfall([ + function(callback){ + callback(null, 'one', 'two'); + }, + function(arg1, arg2, callback){ + callback(null, 'three'); + }, + function(arg1, callback){ + // arg1 now equals 'three' + callback(null, 'done'); + } + ], function (err, result) { + // result now equals 'done' + }); + + +--------------------------------------- + +<a name="queue" /> +### queue(worker, concurrency) + +Creates a queue object with the specified concurrency. Tasks added to the +queue will be processed in parallel (up to the concurrency limit). If all +workers are in progress, the task is queued until one is available. Once +a worker has completed a task, the task's callback is called. + +__Arguments__ + +* worker(task, callback) - An asynchronous function for processing a queued + task. +* concurrency - An integer for determining how many worker functions should be + run in parallel. + +__Queue objects__ + +The queue object returned by this function has the following properties and +methods: + +* length() - a function returning the number of items waiting to be processed. +* concurrency - an integer for determining how many worker functions should be + run in parallel. This property can be changed after a queue is created to + alter the concurrency on-the-fly. +* push(task, [callback]) - add a new task to the queue, the callback is called + once the worker has finished processing the task. + instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list. +* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued +* empty - a callback that is called when the last item from the queue is given to a worker +* drain - a callback that is called when the last item from the queue has returned from the worker + +__Example__ + + // create a queue object with concurrency 2 + + var q = async.queue(function (task, callback) { + console.log('hello ' + task.name); + callback(); + }, 2); + + + // assign a callback + q.drain = function() { + console.log('all items have been processed'); + } + + // add some items to the queue + + q.push({name: 'foo'}, function (err) { + console.log('finished processing foo'); + }); + q.push({name: 'bar'}, function (err) { + console.log('finished processing bar'); + }); + + // add some items to the queue (batch-wise) + + q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) { + console.log('finished processing bar'); + }); + + +--------------------------------------- + +<a name="auto" /> +### auto(tasks, [callback]) + +Determines the best order for running functions based on their requirements. +Each function can optionally depend on other functions being completed first, +and each function is run as soon as its requirements are satisfied. If any of +the functions pass an error to their callback, that function will not complete +(so any other functions depending on it will not run) and the main callback +will be called immediately with the error. Functions also receive an object +containing the results of functions which have completed so far. + +__Arguments__ + +* tasks - An object literal containing named functions or an array of + requirements, with the function itself the last item in the array. The key + used for each function or array is used when specifying requirements. The + syntax is easier to understand by looking at the example. +* callback(err, results) - An optional callback which is called when all the + tasks have been completed. The callback will receive an error as an argument + if any tasks pass an error to their callback. If all tasks complete + successfully, it will receive an object containing their results. + +__Example__ + + async.auto({ + get_data: function(callback){ + // async code to get some data + }, + make_folder: function(callback){ + // async code to create a directory to store a file in + // this is run at the same time as getting the data + }, + write_file: ['get_data', 'make_folder', function(callback){ + // once there is some data and the directory exists, + // write the data to a file in the directory + callback(null, filename); + }], + email_link: ['write_file', function(callback, results){ + // once the file is written let's email a link to it... + // results.write_file contains the filename returned by write_file. + }] + }); + +This is a fairly trivial example, but to do this using the basic parallel and +series functions would look like this: + + async.parallel([ + function(callback){ + // async code to get some data + }, + function(callback){ + // async code to create a directory to store a file in + // this is run at the same time as getting the data + } + ], + function(results){ + async.series([ + function(callback){ + // once there is some data and the directory exists, + // write the data to a file in the directory + }, + email_link: function(callback){ + // once the file is written let's email a link to it... + } + ]); + }); + +For a complicated series of async tasks using the auto function makes adding +new tasks much easier and makes the code more readable. + + +--------------------------------------- + +<a name="iterator" /> +### iterator(tasks) + +Creates an iterator function which calls the next function in the array, +returning a continuation to call the next one after that. Its also possible to +'peek' the next iterator by doing iterator.next(). + +This function is used internally by the async module but can be useful when +you want to manually control the flow of functions in series. + +__Arguments__ + +* tasks - An array of functions to run, each function is passed a callback it + must call on completion. + +__Example__ + + var iterator = async.iterator([ + function(){ sys.p('one'); }, + function(){ sys.p('two'); }, + function(){ sys.p('three'); } + ]); + + node> var iterator2 = iterator(); + 'one' + node> var iterator3 = iterator2(); + 'two' + node> iterator3(); + 'three' + node> var nextfn = iterator2.next(); + node> nextfn(); + 'three' + + +--------------------------------------- + +<a name="apply" /> +### apply(function, arguments..) + +Creates a continuation function with some arguments already applied, a useful +shorthand when combined with other control flow functions. Any arguments +passed to the returned function are added to the arguments originally passed +to apply. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to automatically apply when the + continuation is called. + +__Example__ + + // using apply + + async.parallel([ + async.apply(fs.writeFile, 'testfile1', 'test1'), + async.apply(fs.writeFile, 'testfile2', 'test2'), + ]); + + + // the same process without using apply + + async.parallel([ + function(callback){ + fs.writeFile('testfile1', 'test1', callback); + }, + function(callback){ + fs.writeFile('testfile2', 'test2', callback); + }, + ]); + +It's possible to pass any number of additional arguments when calling the +continuation: + + node> var fn = async.apply(sys.puts, 'one'); + node> fn('two', 'three'); + one + two + three + +--------------------------------------- + +<a name="nextTick" /> +### nextTick(callback) + +Calls the callback on a later loop around the event loop. In node.js this just +calls process.nextTick, in the browser it falls back to setTimeout(callback, 0), +which means other higher priority events may precede the execution of the callback. + +This is used internally for browser-compatibility purposes. + +__Arguments__ + +* callback - The function to call on a later loop around the event loop. + +__Example__ + + var call_order = []; + async.nextTick(function(){ + call_order.push('two'); + // call_order now equals ['one','two] + }); + call_order.push('one') + + +## Utils + +<a name="memoize" /> +### memoize(fn, [hasher]) + +Caches the results of an async function. When creating a hash to store function +results against, the callback is omitted from the hash and an optional hash +function can be used. + +__Arguments__ + +* fn - the function you to proxy and cache results from. +* hasher - an optional function for generating a custom hash for storing + results, it has all the arguments applied to it apart from the callback, and + must be synchronous. + +__Example__ + + var slow_fn = function (name, callback) { + // do something + callback(null, result); + }; + var fn = async.memoize(slow_fn); + + // fn can now be used as if it were slow_fn + fn('some name', function () { + // callback + }); + +<a name="unmemoize" /> +### unmemoize(fn) + +Undoes a memoized function, reverting it to the original, unmemoized +form. Comes handy in tests. + +__Arguments__ + +* fn - the memoized function + +<a name="log" /> +### log(function, arguments) + +Logs the result of an async function to the console. Only works in node.js or +in browsers that support console.log and console.error (such as FF and Chrome). +If multiple arguments are returned from the async function, console.log is +called on each argument in order. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to apply to the function. + +__Example__ + + var hello = function(name, callback){ + setTimeout(function(){ + callback(null, 'hello ' + name); + }, 1000); + }; + + node> async.log(hello, 'world'); + 'hello world' + + +--------------------------------------- + +<a name="dir" /> +### dir(function, arguments) + +Logs the result of an async function to the console using console.dir to +display the properties of the resulting object. Only works in node.js or +in browsers that support console.dir and console.error (such as FF and Chrome). +If multiple arguments are returned from the async function, console.dir is +called on each argument in order. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to apply to the function. + +__Example__ + + var hello = function(name, callback){ + setTimeout(function(){ + callback(null, {hello: name}); + }, 1000); + }; + + node> async.dir(hello, 'world'); + {hello: 'world'} + + +--------------------------------------- + +<a name="noConflict" /> +### noConflict() + +Changes the value of async back to its original value, returning a reference to the +async object. diff --git a/node_modules/request/node_modules/form-data/node_modules/async/index.js b/node_modules/request/node_modules/form-data/node_modules/async/index.js new file mode 100644 index 000000000..8e238453e --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/async/index.js @@ -0,0 +1,3 @@ +// This file is just added for convenience so this repository can be +// directly checked out into a project's deps folder +module.exports = require('./lib/async'); diff --git a/node_modules/request/node_modules/form-data/node_modules/async/lib/async.js b/node_modules/request/node_modules/form-data/node_modules/async/lib/async.js new file mode 100644 index 000000000..7cc4f5eac --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/async/lib/async.js @@ -0,0 +1,692 @@ +/*global setTimeout: false, console: false */ +(function () { + + var async = {}; + + // global on the server, window in the browser + var root = this, + previous_async = root.async; + + if (typeof module !== 'undefined' && module.exports) { + module.exports = async; + } + else { + root.async = async; + } + + async.noConflict = function () { + root.async = previous_async; + return async; + }; + + //// cross-browser compatiblity functions //// + + var _forEach = function (arr, iterator) { + if (arr.forEach) { + return arr.forEach(iterator); + } + for (var i = 0; i < arr.length; i += 1) { + iterator(arr[i], i, arr); + } + }; + + var _map = function (arr, iterator) { + if (arr.map) { + return arr.map(iterator); + } + var results = []; + _forEach(arr, function (x, i, a) { + results.push(iterator(x, i, a)); + }); + return results; + }; + + var _reduce = function (arr, iterator, memo) { + if (arr.reduce) { + return arr.reduce(iterator, memo); + } + _forEach(arr, function (x, i, a) { + memo = iterator(memo, x, i, a); + }); + return memo; + }; + + var _keys = function (obj) { + if (Object.keys) { + return Object.keys(obj); + } + var keys = []; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + keys.push(k); + } + } + return keys; + }; + + //// exported async module functions //// + + //// nextTick implementation with browser-compatible fallback //// + if (typeof process === 'undefined' || !(process.nextTick)) { + async.nextTick = function (fn) { + setTimeout(fn, 0); + }; + } + else { + async.nextTick = process.nextTick; + } + + async.forEach = function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length) { + return callback(); + } + var completed = 0; + _forEach(arr, function (x) { + iterator(x, function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed === arr.length) { + callback(null); + } + } + }); + }); + }; + + async.forEachSeries = function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length) { + return callback(); + } + var completed = 0; + var iterate = function () { + iterator(arr[completed], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed === arr.length) { + callback(null); + } + else { + iterate(); + } + } + }); + }; + iterate(); + }; + + async.forEachLimit = function (arr, limit, iterator, callback) { + callback = callback || function () {}; + if (!arr.length || limit <= 0) { + return callback(); + } + var completed = 0; + var started = 0; + var running = 0; + + (function replenish () { + if (completed === arr.length) { + return callback(); + } + + while (running < limit && started < arr.length) { + started += 1; + running += 1; + iterator(arr[started - 1], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + running -= 1; + if (completed === arr.length) { + callback(); + } + else { + replenish(); + } + } + }); + } + })(); + }; + + + var doParallel = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.forEach].concat(args)); + }; + }; + var doSeries = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.forEachSeries].concat(args)); + }; + }; + + + var _asyncMap = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (err, v) { + results[x.index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + }; + async.map = doParallel(_asyncMap); + async.mapSeries = doSeries(_asyncMap); + + + // reduce only has a series version, as doing reduce in parallel won't + // work in many situations. + async.reduce = function (arr, memo, iterator, callback) { + async.forEachSeries(arr, function (x, callback) { + iterator(memo, x, function (err, v) { + memo = v; + callback(err); + }); + }, function (err) { + callback(err, memo); + }); + }; + // inject alias + async.inject = async.reduce; + // foldl alias + async.foldl = async.reduce; + + async.reduceRight = function (arr, memo, iterator, callback) { + var reversed = _map(arr, function (x) { + return x; + }).reverse(); + async.reduce(reversed, memo, iterator, callback); + }; + // foldr alias + async.foldr = async.reduceRight; + + var _filter = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.filter = doParallel(_filter); + async.filterSeries = doSeries(_filter); + // select alias + async.select = async.filter; + async.selectSeries = async.filterSeries; + + var _reject = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (!v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.reject = doParallel(_reject); + async.rejectSeries = doSeries(_reject); + + var _detect = function (eachfn, arr, iterator, main_callback) { + eachfn(arr, function (x, callback) { + iterator(x, function (result) { + if (result) { + main_callback(x); + main_callback = function () {}; + } + else { + callback(); + } + }); + }, function (err) { + main_callback(); + }); + }; + async.detect = doParallel(_detect); + async.detectSeries = doSeries(_detect); + + async.some = function (arr, iterator, main_callback) { + async.forEach(arr, function (x, callback) { + iterator(x, function (v) { + if (v) { + main_callback(true); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(false); + }); + }; + // any alias + async.any = async.some; + + async.every = function (arr, iterator, main_callback) { + async.forEach(arr, function (x, callback) { + iterator(x, function (v) { + if (!v) { + main_callback(false); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(true); + }); + }; + // all alias + async.all = async.every; + + async.sortBy = function (arr, iterator, callback) { + async.map(arr, function (x, callback) { + iterator(x, function (err, criteria) { + if (err) { + callback(err); + } + else { + callback(null, {value: x, criteria: criteria}); + } + }); + }, function (err, results) { + if (err) { + return callback(err); + } + else { + var fn = function (left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + if (!keys.length) { + return callback(null); + } + + var results = {}; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + _forEach(listeners.slice(0), function (fn) { + fn(); + }); + }; + + addListener(function () { + if (_keys(results).length === keys.length) { + callback(null, results); + callback = function () {}; + } + }); + + _forEach(keys, function (k) { + var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; + var taskCallback = function (err) { + if (err) { + callback(err); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + taskComplete(); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && results.hasOwnProperty(x)); + }, true) && !results.hasOwnProperty(k); + }; + if (ready()) { + task[task.length - 1](taskCallback, results); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback, results); + } + }; + addListener(listener); + } + }); + }; + + async.waterfall = function (tasks, callback) { + callback = callback || function () {}; + if (!tasks.length) { + return callback(); + } + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.nextTick(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + async.parallel = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + async.forEach(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + async.forEachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.queue = function (worker, concurrency) { + var workers = 0; + var q = { + tasks: [], + concurrency: concurrency, + saturated: null, + empty: null, + drain: null, + push: function (data, callback) { + if(data.constructor !== Array) { + data = [data]; + } + _forEach(data, function(task) { + q.tasks.push({ + data: task, + callback: typeof callback === 'function' ? callback : null + }); + if (q.saturated && q.tasks.length == concurrency) { + q.saturated(); + } + async.nextTick(q.process); + }); + }, + process: function () { + if (workers < q.concurrency && q.tasks.length) { + var task = q.tasks.shift(); + if(q.empty && q.tasks.length == 0) q.empty(); + workers += 1; + worker(task.data, function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + if(q.drain && q.tasks.length + workers == 0) q.drain(); + q.process(); + }); + } + }, + length: function () { + return q.tasks.length; + }, + running: function () { + return workers; + } + }; + return q; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _forEach(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + var queues = {}; + hasher = hasher || function (x) { + return x; + }; + var memoized = function () { + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + callback.apply(null, memo[key]); + } + else if (key in queues) { + queues[key].push(callback); + } + else { + queues[key] = [callback]; + fn.apply(null, args.concat([function () { + memo[key] = arguments; + var q = queues[key]; + delete queues[key]; + for (var i = 0, l = q.length; i < l; i++) { + q[i].apply(null, arguments); + } + }])); + } + }; + memoized.unmemoized = fn; + return memoized; + }; + + async.unmemoize = function (fn) { + return function () { + return (fn.unmemoized || fn).apply(null, arguments); + }; + }; + +}()); diff --git a/node_modules/request/node_modules/form-data/node_modules/async/package.json b/node_modules/request/node_modules/form-data/node_modules/async/package.json new file mode 100644 index 000000000..339caef6b --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/async/package.json @@ -0,0 +1,35 @@ +{ + "name": "async", + "description": "Higher-order functions and common patterns for asynchronous code", + "main": "./index", + "author": { + "name": "Caolan McMahon" + }, + "version": "0.1.22", + "repository": { + "type": "git", + "url": "http://github.com/caolan/async.git" + }, + "bugs": { + "url": "http://github.com/caolan/async/issues" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/caolan/async/raw/master/LICENSE" + } + ], + "devDependencies": { + "nodeunit": ">0.0.0", + "uglify-js": "1.2.x", + "nodelint": ">0.0.0" + }, + "readme": "# Async.js\n\nAsync is a utility module which provides straight-forward, powerful functions\nfor working with asynchronous JavaScript. Although originally designed for\nuse with [node.js](http://nodejs.org), it can also be used directly in the\nbrowser.\n\nAsync provides around 20 functions that include the usual 'functional'\nsuspects (map, reduce, filter, forEach…) as well as some common patterns\nfor asynchronous control flow (parallel, series, waterfall…). All these\nfunctions assume you follow the node.js convention of providing a single\ncallback as the last argument of your async function.\n\n\n## Quick Examples\n\n async.map(['file1','file2','file3'], fs.stat, function(err, results){\n // results is now an array of stats for each file\n });\n\n async.filter(['file1','file2','file3'], path.exists, function(results){\n // results now equals an array of the existing files\n });\n\n async.parallel([\n function(){ ... },\n function(){ ... }\n ], callback);\n\n async.series([\n function(){ ... },\n function(){ ... }\n ]);\n\nThere are many more functions available so take a look at the docs below for a\nfull list. This module aims to be comprehensive, so if you feel anything is\nmissing please create a GitHub issue for it.\n\n\n## Download\n\nReleases are available for download from\n[GitHub](http://github.com/caolan/async/downloads).\nAlternatively, you can install using Node Package Manager (npm):\n\n npm install async\n\n\n__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 17.5kb Uncompressed\n\n__Production:__ [async.min.js](https://github.com/caolan/async/raw/master/dist/async.min.js) - 1.7kb Packed and Gzipped\n\n\n## In the Browser\n\nSo far its been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:\n\n <script type=\"text/javascript\" src=\"async.js\"></script>\n <script type=\"text/javascript\">\n\n async.map(data, asyncProcess, function(err, results){\n alert(results);\n });\n\n </script>\n\n\n## Documentation\n\n### Collections\n\n* [forEach](#forEach)\n* [map](#map)\n* [filter](#filter)\n* [reject](#reject)\n* [reduce](#reduce)\n* [detect](#detect)\n* [sortBy](#sortBy)\n* [some](#some)\n* [every](#every)\n* [concat](#concat)\n\n### Control Flow\n\n* [series](#series)\n* [parallel](#parallel)\n* [whilst](#whilst)\n* [until](#until)\n* [waterfall](#waterfall)\n* [queue](#queue)\n* [auto](#auto)\n* [iterator](#iterator)\n* [apply](#apply)\n* [nextTick](#nextTick)\n\n### Utils\n\n* [memoize](#memoize)\n* [unmemoize](#unmemoize)\n* [log](#log)\n* [dir](#dir)\n* [noConflict](#noConflict)\n\n\n## Collections\n\n<a name=\"forEach\" />\n### forEach(arr, iterator, callback)\n\nApplies an iterator function to each item in an array, in parallel.\nThe iterator is called with an item from the list and a callback for when it\nhas finished. If the iterator passes an error to this callback, the main\ncallback for the forEach function is immediately called with the error.\n\nNote, that since this function applies the iterator to each item in parallel\nthere is no guarantee that the iterator functions will complete in order.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed.\n* callback(err) - A callback which is called after all the iterator functions\n have finished, or an error has occurred.\n\n__Example__\n\n // assuming openFiles is an array of file names and saveFile is a function\n // to save the modified contents of that file:\n\n async.forEach(openFiles, saveFile, function(err){\n // if any of the saves produced an error, err would equal that error\n });\n\n---------------------------------------\n\n<a name=\"forEachSeries\" />\n### forEachSeries(arr, iterator, callback)\n\nThe same as forEach only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. This means the iterator functions will complete in order.\n\n\n---------------------------------------\n\n<a name=\"forEachLimit\" />\n### forEachLimit(arr, limit, iterator, callback)\n\nThe same as forEach only the iterator is applied to batches of items in the\narray, in series. The next batch of iterators is only called once the current\none has completed processing.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* limit - How many items should be in each batch.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed.\n* callback(err) - A callback which is called after all the iterator functions\n have finished, or an error has occurred.\n\n__Example__\n\n // Assume documents is an array of JSON objects and requestApi is a\n // function that interacts with a rate-limited REST api.\n\n async.forEachLimit(documents, 20, requestApi, function(err){\n // if any of the saves produced an error, err would equal that error\n });\n---------------------------------------\n\n<a name=\"map\" />\n### map(arr, iterator, callback)\n\nProduces a new array of values by mapping each value in the given array through\nthe iterator function. The iterator is called with an item from the array and a\ncallback for when it has finished processing. The callback takes 2 arguments, \nan error and the transformed item from the array. If the iterator passes an\nerror to this callback, the main callback for the map function is immediately\ncalled with the error.\n\nNote, that since this function applies the iterator to each item in parallel\nthere is no guarantee that the iterator functions will complete in order, however\nthe results array will be in the same order as the original array.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed\n with an error (which can be null) and a transformed item.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is an array of the\n transformed items from the original array.\n\n__Example__\n\n async.map(['file1','file2','file3'], fs.stat, function(err, results){\n // results is now an array of stats for each file\n });\n\n---------------------------------------\n\n<a name=\"mapSeries\" />\n### mapSeries(arr, iterator, callback)\n\nThe same as map only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n\n---------------------------------------\n\n<a name=\"filter\" />\n### filter(arr, iterator, callback)\n\n__Alias:__ select\n\nReturns a new array of all the values which pass an async truth test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like path.exists. This operation is\nperformed in parallel, but the results array will be in the same order as the\noriginal.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed.\n* callback(results) - A callback which is called after all the iterator\n functions have finished.\n\n__Example__\n\n async.filter(['file1','file2','file3'], path.exists, function(results){\n // results now equals an array of the existing files\n });\n\n---------------------------------------\n\n<a name=\"filterSeries\" />\n### filterSeries(arr, iterator, callback)\n\n__alias:__ selectSeries\n\nThe same as filter only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n---------------------------------------\n\n<a name=\"reject\" />\n### reject(arr, iterator, callback)\n\nThe opposite of filter. Removes values that pass an async truth test.\n\n---------------------------------------\n\n<a name=\"rejectSeries\" />\n### rejectSeries(arr, iterator, callback)\n\nThe same as filter, only the iterator is applied to each item in the array\nin series.\n\n\n---------------------------------------\n\n<a name=\"reduce\" />\n### reduce(arr, memo, iterator, callback)\n\n__aliases:__ inject, foldl\n\nReduces a list of values into a single value using an async iterator to return\neach successive step. Memo is the initial state of the reduction. This\nfunction only operates in series. For performance reasons, it may make sense to\nsplit a call to this function into a parallel map, then use the normal\nArray.prototype.reduce on the results. This function is for situations where\neach step in the reduction needs to be async, if you can get the data before\nreducing it then its probably a good idea to do so.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* memo - The initial state of the reduction.\n* iterator(memo, item, callback) - A function applied to each item in the\n array to produce the next step in the reduction. The iterator is passed a\n callback which accepts an optional error as its first argument, and the state\n of the reduction as the second. If an error is passed to the callback, the\n reduction is stopped and the main callback is immediately called with the\n error.\n* callback(err, result) - A callback which is called after all the iterator\n functions have finished. Result is the reduced value.\n\n__Example__\n\n async.reduce([1,2,3], 0, function(memo, item, callback){\n // pointless async:\n process.nextTick(function(){\n callback(null, memo + item)\n });\n }, function(err, result){\n // result is now equal to the last value of memo, which is 6\n });\n\n---------------------------------------\n\n<a name=\"reduceRight\" />\n### reduceRight(arr, memo, iterator, callback)\n\n__Alias:__ foldr\n\nSame as reduce, only operates on the items in the array in reverse order.\n\n\n---------------------------------------\n\n<a name=\"detect\" />\n### detect(arr, iterator, callback)\n\nReturns the first value in a list that passes an async truth test. The\niterator is applied in parallel, meaning the first iterator to return true will\nfire the detect callback with that result. That means the result might not be\nthe first item in the original array (in terms of order) that passes the test.\n\nIf order within the original array is important then look at detectSeries.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed.\n* callback(result) - A callback which is called as soon as any iterator returns\n true, or after all the iterator functions have finished. Result will be\n the first item in the array that passes the truth test (iterator) or the\n value undefined if none passed.\n\n__Example__\n\n async.detect(['file1','file2','file3'], path.exists, function(result){\n // result now equals the first file in the list that exists\n });\n\n---------------------------------------\n\n<a name=\"detectSeries\" />\n### detectSeries(arr, iterator, callback)\n\nThe same as detect, only the iterator is applied to each item in the array\nin series. This means the result is always the first in the original array (in\nterms of array order) that passes the truth test.\n\n\n---------------------------------------\n\n<a name=\"sortBy\" />\n### sortBy(arr, iterator, callback)\n\nSorts a list by the results of running each value through an async iterator.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed\n with an error (which can be null) and a value to use as the sort criteria.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is the items from\n the original array sorted by the values returned by the iterator calls.\n\n__Example__\n\n async.sortBy(['file1','file2','file3'], function(file, callback){\n fs.stat(file, function(err, stats){\n callback(err, stats.mtime);\n });\n }, function(err, results){\n // results is now the original array of files sorted by\n // modified date\n });\n\n\n---------------------------------------\n\n<a name=\"some\" />\n### some(arr, iterator, callback)\n\n__Alias:__ any\n\nReturns true if at least one element in the array satisfies an async test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like path.exists. Once any iterator\ncall returns true, the main callback is immediately called.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed.\n* callback(result) - A callback which is called as soon as any iterator returns\n true, or after all the iterator functions have finished. Result will be\n either true or false depending on the values of the async tests.\n\n__Example__\n\n async.some(['file1','file2','file3'], path.exists, function(result){\n // if result is true then at least one of the files exists\n });\n\n---------------------------------------\n\n<a name=\"every\" />\n### every(arr, iterator, callback)\n\n__Alias:__ all\n\nReturns true if every element in the array satisfies an async test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like path.exists.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed.\n* callback(result) - A callback which is called after all the iterator\n functions have finished. Result will be either true or false depending on\n the values of the async tests.\n\n__Example__\n\n async.every(['file1','file2','file3'], path.exists, function(result){\n // if result is true then every file exists\n });\n\n---------------------------------------\n\n<a name=\"concat\" />\n### concat(arr, iterator, callback)\n\nApplies an iterator to each item in a list, concatenating the results. Returns the\nconcatenated list. The iterators are called in parallel, and the results are\nconcatenated as they return. There is no guarantee that the results array will\nbe returned in the original order of the arguments passed to the iterator function.\n\n__Arguments__\n\n* arr - An array to iterate over\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback which must be called once it has completed\n with an error (which can be null) and an array of results.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is an array containing\n the concatenated results of the iterator function.\n\n__Example__\n\n async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){\n // files is now a list of filenames that exist in the 3 directories\n });\n\n---------------------------------------\n\n<a name=\"concatSeries\" />\n### concatSeries(arr, iterator, callback)\n\nSame as async.concat, but executes in series instead of parallel.\n\n\n## Control Flow\n\n<a name=\"series\" />\n### series(tasks, [callback])\n\nRun an array of functions in series, each one running once the previous\nfunction has completed. If any functions in the series pass an error to its\ncallback, no more functions are run and the callback for the series is\nimmediately called with the value of the error. Once the tasks have completed,\nthe results are passed to the final callback as an array.\n\nIt is also possible to use an object instead of an array. Each property will be\nrun as a function and the results will be passed to the final callback as an object\ninstead of an array. This can be a more readable way of handling results from\nasync.series.\n\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed\n a callback it must call on completion.\n* callback(err, results) - An optional callback to run once all the functions\n have completed. This function gets an array of all the arguments passed to\n the callbacks used in the array.\n\n__Example__\n\n async.series([\n function(callback){\n // do some stuff ...\n callback(null, 'one');\n },\n function(callback){\n // do some more stuff ...\n callback(null, 'two');\n },\n ],\n // optional callback\n function(err, results){\n // results is now equal to ['one', 'two']\n });\n\n\n // an example using an object instead of an array\n async.series({\n one: function(callback){\n setTimeout(function(){\n callback(null, 1);\n }, 200);\n },\n two: function(callback){\n setTimeout(function(){\n callback(null, 2);\n }, 100);\n },\n },\n function(err, results) {\n // results is now equal to: {one: 1, two: 2}\n });\n\n\n---------------------------------------\n\n<a name=\"parallel\" />\n### parallel(tasks, [callback])\n\nRun an array of functions in parallel, without waiting until the previous\nfunction has completed. If any of the functions pass an error to its\ncallback, the main callback is immediately called with the value of the error.\nOnce the tasks have completed, the results are passed to the final callback as an\narray.\n\nIt is also possible to use an object instead of an array. Each property will be\nrun as a function and the results will be passed to the final callback as an object\ninstead of an array. This can be a more readable way of handling results from\nasync.parallel.\n\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed a\n callback it must call on completion.\n* callback(err, results) - An optional callback to run once all the functions\n have completed. This function gets an array of all the arguments passed to\n the callbacks used in the array.\n\n__Example__\n\n async.parallel([\n function(callback){\n setTimeout(function(){\n callback(null, 'one');\n }, 200);\n },\n function(callback){\n setTimeout(function(){\n callback(null, 'two');\n }, 100);\n },\n ],\n // optional callback\n function(err, results){\n // the results array will equal ['one','two'] even though\n // the second function had a shorter timeout.\n });\n\n\n // an example using an object instead of an array\n async.parallel({\n one: function(callback){\n setTimeout(function(){\n callback(null, 1);\n }, 200);\n },\n two: function(callback){\n setTimeout(function(){\n callback(null, 2);\n }, 100);\n },\n },\n function(err, results) {\n // results is now equals to: {one: 1, two: 2}\n });\n\n\n---------------------------------------\n\n<a name=\"whilst\" />\n### whilst(test, fn, callback)\n\nRepeatedly call fn, while test returns true. Calls the callback when stopped,\nor an error occurs.\n\n__Arguments__\n\n* test() - synchronous truth test to perform before each execution of fn.\n* fn(callback) - A function to call each time the test passes. The function is\n passed a callback which must be called once it has completed with an optional\n error as the first argument.\n* callback(err) - A callback which is called after the test fails and repeated\n execution of fn has stopped.\n\n__Example__\n\n var count = 0;\n\n async.whilst(\n function () { return count < 5; },\n function (callback) {\n count++;\n setTimeout(callback, 1000);\n },\n function (err) {\n // 5 seconds have passed\n }\n );\n\n\n---------------------------------------\n\n<a name=\"until\" />\n### until(test, fn, callback)\n\nRepeatedly call fn, until test returns true. Calls the callback when stopped,\nor an error occurs.\n\nThe inverse of async.whilst.\n\n\n---------------------------------------\n\n<a name=\"waterfall\" />\n### waterfall(tasks, [callback])\n\nRuns an array of functions in series, each passing their results to the next in\nthe array. However, if any of the functions pass an error to the callback, the\nnext function is not executed and the main callback is immediately called with\nthe error.\n\n__Arguments__\n\n* tasks - An array of functions to run, each function is passed a callback it\n must call on completion.\n* callback(err, [results]) - An optional callback to run once all the functions\n have completed. This will be passed the results of the last task's callback.\n\n\n\n__Example__\n\n async.waterfall([\n function(callback){\n callback(null, 'one', 'two');\n },\n function(arg1, arg2, callback){\n callback(null, 'three');\n },\n function(arg1, callback){\n // arg1 now equals 'three'\n callback(null, 'done');\n }\n ], function (err, result) {\n // result now equals 'done' \n });\n\n\n---------------------------------------\n\n<a name=\"queue\" />\n### queue(worker, concurrency)\n\nCreates a queue object with the specified concurrency. Tasks added to the\nqueue will be processed in parallel (up to the concurrency limit). If all\nworkers are in progress, the task is queued until one is available. Once\na worker has completed a task, the task's callback is called.\n\n__Arguments__\n\n* worker(task, callback) - An asynchronous function for processing a queued\n task.\n* concurrency - An integer for determining how many worker functions should be\n run in parallel.\n\n__Queue objects__\n\nThe queue object returned by this function has the following properties and\nmethods:\n\n* length() - a function returning the number of items waiting to be processed.\n* concurrency - an integer for determining how many worker functions should be\n run in parallel. This property can be changed after a queue is created to\n alter the concurrency on-the-fly.\n* push(task, [callback]) - add a new task to the queue, the callback is called\n once the worker has finished processing the task.\n instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.\n* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued\n* empty - a callback that is called when the last item from the queue is given to a worker\n* drain - a callback that is called when the last item from the queue has returned from the worker\n\n__Example__\n\n // create a queue object with concurrency 2\n\n var q = async.queue(function (task, callback) {\n console.log('hello ' + task.name);\n callback();\n }, 2);\n\n\n // assign a callback\n q.drain = function() {\n console.log('all items have been processed');\n }\n\n // add some items to the queue\n\n q.push({name: 'foo'}, function (err) {\n console.log('finished processing foo');\n });\n q.push({name: 'bar'}, function (err) {\n console.log('finished processing bar');\n });\n\n // add some items to the queue (batch-wise)\n\n q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {\n console.log('finished processing bar');\n });\n\n\n---------------------------------------\n\n<a name=\"auto\" />\n### auto(tasks, [callback])\n\nDetermines the best order for running functions based on their requirements.\nEach function can optionally depend on other functions being completed first,\nand each function is run as soon as its requirements are satisfied. If any of\nthe functions pass an error to their callback, that function will not complete\n(so any other functions depending on it will not run) and the main callback\nwill be called immediately with the error. Functions also receive an object\ncontaining the results of functions which have completed so far.\n\n__Arguments__\n\n* tasks - An object literal containing named functions or an array of\n requirements, with the function itself the last item in the array. The key\n used for each function or array is used when specifying requirements. The\n syntax is easier to understand by looking at the example.\n* callback(err, results) - An optional callback which is called when all the\n tasks have been completed. The callback will receive an error as an argument\n if any tasks pass an error to their callback. If all tasks complete\n successfully, it will receive an object containing their results.\n\n__Example__\n\n async.auto({\n get_data: function(callback){\n // async code to get some data\n },\n make_folder: function(callback){\n // async code to create a directory to store a file in\n // this is run at the same time as getting the data\n },\n write_file: ['get_data', 'make_folder', function(callback){\n // once there is some data and the directory exists,\n // write the data to a file in the directory\n callback(null, filename);\n }],\n email_link: ['write_file', function(callback, results){\n // once the file is written let's email a link to it...\n // results.write_file contains the filename returned by write_file.\n }]\n });\n\nThis is a fairly trivial example, but to do this using the basic parallel and\nseries functions would look like this:\n\n async.parallel([\n function(callback){\n // async code to get some data\n },\n function(callback){\n // async code to create a directory to store a file in\n // this is run at the same time as getting the data\n }\n ],\n function(results){\n async.series([\n function(callback){\n // once there is some data and the directory exists,\n // write the data to a file in the directory\n },\n email_link: function(callback){\n // once the file is written let's email a link to it...\n }\n ]);\n });\n\nFor a complicated series of async tasks using the auto function makes adding\nnew tasks much easier and makes the code more readable.\n\n\n---------------------------------------\n\n<a name=\"iterator\" />\n### iterator(tasks)\n\nCreates an iterator function which calls the next function in the array,\nreturning a continuation to call the next one after that. Its also possible to\n'peek' the next iterator by doing iterator.next().\n\nThis function is used internally by the async module but can be useful when\nyou want to manually control the flow of functions in series.\n\n__Arguments__\n\n* tasks - An array of functions to run, each function is passed a callback it\n must call on completion.\n\n__Example__\n\n var iterator = async.iterator([\n function(){ sys.p('one'); },\n function(){ sys.p('two'); },\n function(){ sys.p('three'); }\n ]);\n\n node> var iterator2 = iterator();\n 'one'\n node> var iterator3 = iterator2();\n 'two'\n node> iterator3();\n 'three'\n node> var nextfn = iterator2.next();\n node> nextfn();\n 'three'\n\n\n---------------------------------------\n\n<a name=\"apply\" />\n### apply(function, arguments..)\n\nCreates a continuation function with some arguments already applied, a useful\nshorthand when combined with other control flow functions. Any arguments\npassed to the returned function are added to the arguments originally passed\nto apply.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to automatically apply when the\n continuation is called.\n\n__Example__\n\n // using apply\n\n async.parallel([\n async.apply(fs.writeFile, 'testfile1', 'test1'),\n async.apply(fs.writeFile, 'testfile2', 'test2'),\n ]);\n\n\n // the same process without using apply\n\n async.parallel([\n function(callback){\n fs.writeFile('testfile1', 'test1', callback);\n },\n function(callback){\n fs.writeFile('testfile2', 'test2', callback);\n },\n ]);\n\nIt's possible to pass any number of additional arguments when calling the\ncontinuation:\n\n node> var fn = async.apply(sys.puts, 'one');\n node> fn('two', 'three');\n one\n two\n three\n\n---------------------------------------\n\n<a name=\"nextTick\" />\n### nextTick(callback)\n\nCalls the callback on a later loop around the event loop. In node.js this just\ncalls process.nextTick, in the browser it falls back to setTimeout(callback, 0),\nwhich means other higher priority events may precede the execution of the callback.\n\nThis is used internally for browser-compatibility purposes.\n\n__Arguments__\n\n* callback - The function to call on a later loop around the event loop.\n\n__Example__\n\n var call_order = [];\n async.nextTick(function(){\n call_order.push('two');\n // call_order now equals ['one','two]\n });\n call_order.push('one')\n\n\n## Utils\n\n<a name=\"memoize\" />\n### memoize(fn, [hasher])\n\nCaches the results of an async function. When creating a hash to store function\nresults against, the callback is omitted from the hash and an optional hash\nfunction can be used.\n\n__Arguments__\n\n* fn - the function you to proxy and cache results from.\n* hasher - an optional function for generating a custom hash for storing\n results, it has all the arguments applied to it apart from the callback, and\n must be synchronous.\n\n__Example__\n\n var slow_fn = function (name, callback) {\n // do something\n callback(null, result);\n };\n var fn = async.memoize(slow_fn);\n\n // fn can now be used as if it were slow_fn\n fn('some name', function () {\n // callback\n });\n\n<a name=\"unmemoize\" />\n### unmemoize(fn)\n\nUndoes a memoized function, reverting it to the original, unmemoized\nform. Comes handy in tests.\n\n__Arguments__\n\n* fn - the memoized function\n\n<a name=\"log\" />\n### log(function, arguments)\n\nLogs the result of an async function to the console. Only works in node.js or\nin browsers that support console.log and console.error (such as FF and Chrome).\nIf multiple arguments are returned from the async function, console.log is\ncalled on each argument in order.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to apply to the function.\n\n__Example__\n\n var hello = function(name, callback){\n setTimeout(function(){\n callback(null, 'hello ' + name);\n }, 1000);\n };\n\n node> async.log(hello, 'world');\n 'hello world'\n\n\n---------------------------------------\n\n<a name=\"dir\" />\n### dir(function, arguments)\n\nLogs the result of an async function to the console using console.dir to\ndisplay the properties of the resulting object. Only works in node.js or\nin browsers that support console.dir and console.error (such as FF and Chrome).\nIf multiple arguments are returned from the async function, console.dir is\ncalled on each argument in order.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to apply to the function.\n\n__Example__\n\n var hello = function(name, callback){\n setTimeout(function(){\n callback(null, {hello: name});\n }, 1000);\n };\n\n node> async.dir(hello, 'world');\n {hello: 'world'}\n\n\n---------------------------------------\n\n<a name=\"noConflict\" />\n### noConflict()\n\nChanges the value of async back to its original value, returning a reference to the\nasync object.\n", + "readmeFilename": "README.md", + "_id": "async@0.1.22", + "dist": { + "shasum": "9410ff209b32d640cd9397f25fb77c2c634d60cc" + }, + "_from": "async@~0.1.9", + "_resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz" +} diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/.npmignore b/node_modules/request/node_modules/form-data/node_modules/combined-stream/.npmignore new file mode 100644 index 000000000..aba34f012 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/.npmignore @@ -0,0 +1,3 @@ +*.un~ +/node_modules +/test/tmp diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/License b/node_modules/request/node_modules/form-data/node_modules/combined-stream/License new file mode 100644 index 000000000..4804b7ab4 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/License @@ -0,0 +1,19 @@ +Copyright (c) 2011 Debuggable Limited <felix@debuggable.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/Makefile b/node_modules/request/node_modules/form-data/node_modules/combined-stream/Makefile new file mode 100644 index 000000000..b4ff85a33 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/Makefile @@ -0,0 +1,7 @@ +SHELL := /bin/bash + +test: + @./test/run.js + +.PHONY: test + diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/Readme.md b/node_modules/request/node_modules/form-data/node_modules/combined-stream/Readme.md new file mode 100644 index 000000000..1a9999eb0 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/Readme.md @@ -0,0 +1,132 @@ +# combined-stream + +A stream that emits multiple other streams one after another. + +## Installation + +``` bash +npm install combined-stream +``` + +## Usage + +Here is a simple example that shows how you can use combined-stream to combine +two files into one: + +``` javascript +var CombinedStream = require('combined-stream'); +var fs = require('fs'); + +var combinedStream = CombinedStream.create(); +combinedStream.append(fs.createReadStream('file1.txt')); +combinedStream.append(fs.createReadStream('file2.txt')); + +combinedStream.pipe(fs.createWriteStream('combined.txt')); +``` + +While the example above works great, it will pause all source streams until +they are needed. If you don't want that to happen, you can set `pauseStreams` +to `false`: + +``` javascript +var CombinedStream = require('combined-stream'); +var fs = require('fs'); + +var combinedStream = CombinedStream.create({pauseStreams: false}); +combinedStream.append(fs.createReadStream('file1.txt')); +combinedStream.append(fs.createReadStream('file2.txt')); + +combinedStream.pipe(fs.createWriteStream('combined.txt')); +``` + +However, what if you don't have all the source streams yet, or you don't want +to allocate the resources (file descriptors, memory, etc.) for them right away? +Well, in that case you can simply provide a callback that supplies the stream +by calling a `next()` function: + +``` javascript +var CombinedStream = require('combined-stream'); +var fs = require('fs'); + +var combinedStream = CombinedStream.create(); +combinedStream.append(function(next) { + next(fs.createReadStream('file1.txt')); +}); +combinedStream.append(function(next) { + next(fs.createReadStream('file2.txt')); +}); + +combinedStream.pipe(fs.createWriteStream('combined.txt')); +``` + +## API + +### CombinedStream.create([options]) + +Returns a new combined stream object. Available options are: + +* `maxDataSize` +* `pauseStreams` + +The effect of those options is described below. + +### combinedStream.pauseStreams = true + +Whether to apply back pressure to the underlaying streams. If set to `false`, +the underlaying streams will never be paused. If set to `true`, the +underlaying streams will be paused right after being appended, as well as when +`delayedStream.pipe()` wants to throttle. + +### combinedStream.maxDataSize = 2 * 1024 * 1024 + +The maximum amount of bytes (or characters) to buffer for all source streams. +If this value is exceeded, `combinedStream` emits an `'error'` event. + +### combinedStream.dataSize = 0 + +The amount of bytes (or characters) currently buffered by `combinedStream`. + +### combinedStream.append(stream) + +Appends the given `stream` to the combinedStream object. If `pauseStreams` is +set to `true, this stream will also be paused right away. + +`streams` can also be a function that takes one parameter called `next`. `next` +is a function that must be invoked in order to provide the `next` stream, see +example above. + +Regardless of how the `stream` is appended, combined-stream always attaches an +`'error'` listener to it, so you don't have to do that manually. + +Special case: `stream` can also be a String or Buffer. + +### combinedStream.write(data) + +You should not call this, `combinedStream` takes care of piping the appended +streams into itself for you. + +### combinedStream.resume() + +Causes `combinedStream` to start drain the streams it manages. The function is +idempotent, and also emits a `'resume'` event each time which usually goes to +the stream that is currently being drained. + +### combinedStream.pause(); + +If `combinedStream.pauseStreams` is set to `false`, this does nothing. +Otherwise a `'pause'` event is emitted, this goes to the stream that is +currently being drained, so you can use it to apply back pressure. + +### combinedStream.end(); + +Sets `combinedStream.writable` to false, emits an `'end'` event, and removes +all streams from the queue. + +### combinedStream.destroy(); + +Same as `combinedStream.end()`, except it emits a `'close'` event instead of +`'end'`. + +## License + +combined-stream is licensed under the MIT license. diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/lib/combined_stream.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/lib/combined_stream.js new file mode 100644 index 000000000..32849fd10 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/lib/combined_stream.js @@ -0,0 +1,185 @@ +var util = require('util'); +var Stream = require('stream').Stream; +var DelayedStream = require('delayed-stream'); + +module.exports = CombinedStream; +function CombinedStream() { + this.writable = false; + this.readable = true; + this.dataSize = 0; + this.maxDataSize = 2 * 1024 * 1024; + this.pauseStreams = true; + + this._released = false; + this._streams = []; + this._currentStream = null; +} +util.inherits(CombinedStream, Stream); + +CombinedStream.create = function(options) { + var combinedStream = new this(); + + options = options || {}; + for (var option in options) { + combinedStream[option] = options[option]; + } + + return combinedStream; +}; + +CombinedStream.isStreamLike = function(stream) { + return (typeof stream !== 'function') + && (typeof stream !== 'string') + && (typeof stream !== 'boolean') + && (typeof stream !== 'number') + && (!Buffer.isBuffer(stream)); +}; + +CombinedStream.prototype.append = function(stream) { + var isStreamLike = CombinedStream.isStreamLike(stream); + + if (isStreamLike) { + if (!(stream instanceof DelayedStream)) { + stream.on('data', this._checkDataSize.bind(this)); + + stream = DelayedStream.create(stream, { + maxDataSize: Infinity, + pauseStream: this.pauseStreams, + }); + } + + this._handleErrors(stream); + + if (this.pauseStreams) { + stream.pause(); + } + } + + this._streams.push(stream); + return this; +}; + +CombinedStream.prototype.pipe = function(dest, options) { + Stream.prototype.pipe.call(this, dest, options); + this.resume(); +}; + +CombinedStream.prototype._getNext = function() { + this._currentStream = null; + var stream = this._streams.shift(); + + + if (typeof stream == 'undefined') { + this.end(); + return; + } + + if (typeof stream !== 'function') { + this._pipeNext(stream); + return; + } + + var getStream = stream; + getStream(function(stream) { + var isStreamLike = CombinedStream.isStreamLike(stream); + if (isStreamLike) { + stream.on('data', this._checkDataSize.bind(this)); + this._handleErrors(stream); + } + + this._pipeNext(stream); + }.bind(this)); +}; + +CombinedStream.prototype._pipeNext = function(stream) { + this._currentStream = stream; + + var isStreamLike = CombinedStream.isStreamLike(stream); + if (isStreamLike) { + stream.on('end', this._getNext.bind(this)) + stream.pipe(this, {end: false}); + return; + } + + var value = stream; + this.write(value); + this._getNext(); +}; + +CombinedStream.prototype._handleErrors = function(stream) { + var self = this; + stream.on('error', function(err) { + self._emitError(err); + }); +}; + +CombinedStream.prototype.write = function(data) { + this.emit('data', data); +}; + +CombinedStream.prototype.pause = function() { + if (!this.pauseStreams) { + return; + } + + this.emit('pause'); +}; + +CombinedStream.prototype.resume = function() { + if (!this._released) { + this._released = true; + this.writable = true; + this._getNext(); + } + + this.emit('resume'); +}; + +CombinedStream.prototype.end = function() { + this._reset(); + this.emit('end'); +}; + +CombinedStream.prototype.destroy = function() { + this._reset(); + this.emit('close'); +}; + +CombinedStream.prototype._reset = function() { + this.writable = false; + this._streams = []; + this._currentStream = null; +}; + +CombinedStream.prototype._checkDataSize = function() { + this._updateDataSize(); + if (this.dataSize <= this.maxDataSize) { + return; + } + + var message = + 'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.' + this._emitError(new Error(message)); +}; + +CombinedStream.prototype._updateDataSize = function() { + this.dataSize = 0; + + var self = this; + this._streams.forEach(function(stream) { + if (!stream.dataSize) { + return; + } + + self.dataSize += stream.dataSize; + }); + + if (this._currentStream && this._currentStream.dataSize) { + this.dataSize += this._currentStream.dataSize; + } +}; + +CombinedStream.prototype._emitError = function(err) { + this._reset(); + this.emit('error', err); +}; diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/.npmignore b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/.npmignore new file mode 100644 index 000000000..2fedb26cc --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/.npmignore @@ -0,0 +1,2 @@ +*.un~ +/node_modules/* diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/License b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/License new file mode 100644 index 000000000..4804b7ab4 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/License @@ -0,0 +1,19 @@ +Copyright (c) 2011 Debuggable Limited <felix@debuggable.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Makefile b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Makefile new file mode 100644 index 000000000..b4ff85a33 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Makefile @@ -0,0 +1,7 @@ +SHELL := /bin/bash + +test: + @./test/run.js + +.PHONY: test + diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Readme.md b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Readme.md new file mode 100644 index 000000000..5cb5b35e5 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/Readme.md @@ -0,0 +1,154 @@ +# delayed-stream + +Buffers events from a stream until you are ready to handle them. + +## Installation + +``` bash +npm install delayed-stream +``` + +## Usage + +The following example shows how to write a http echo server that delays its +response by 1000 ms. + +``` javascript +var DelayedStream = require('delayed-stream'); +var http = require('http'); + +http.createServer(function(req, res) { + var delayed = DelayedStream.create(req); + + setTimeout(function() { + res.writeHead(200); + delayed.pipe(res); + }, 1000); +}); +``` + +If you are not using `Stream#pipe`, you can also manually release the buffered +events by calling `delayedStream.resume()`: + +``` javascript +var delayed = DelayedStream.create(req); + +setTimeout(function() { + // Emit all buffered events and resume underlaying source + delayed.resume(); +}, 1000); +``` + +## Implementation + +In order to use this meta stream properly, here are a few things you should +know about the implementation. + +### Event Buffering / Proxying + +All events of the `source` stream are hijacked by overwriting the `source.emit` +method. Until node implements a catch-all event listener, this is the only way. + +However, delayed-stream still continues to emit all events it captures on the +`source`, regardless of whether you have released the delayed stream yet or +not. + +Upon creation, delayed-stream captures all `source` events and stores them in +an internal event buffer. Once `delayedStream.release()` is called, all +buffered events are emitted on the `delayedStream`, and the event buffer is +cleared. After that, delayed-stream merely acts as a proxy for the underlaying +source. + +### Error handling + +Error events on `source` are buffered / proxied just like any other events. +However, `delayedStream.create` attaches a no-op `'error'` listener to the +`source`. This way you only have to handle errors on the `delayedStream` +object, rather than in two places. + +### Buffer limits + +delayed-stream provides a `maxDataSize` property that can be used to limit +the amount of data being buffered. In order to protect you from bad `source` +streams that don't react to `source.pause()`, this feature is enabled by +default. + +## API + +### DelayedStream.create(source, [options]) + +Returns a new `delayedStream`. Available options are: + +* `pauseStream` +* `maxDataSize` + +The description for those properties can be found below. + +### delayedStream.source + +The `source` stream managed by this object. This is useful if you are +passing your `delayedStream` around, and you still want to access properties +on the `source` object. + +### delayedStream.pauseStream = true + +Whether to pause the underlaying `source` when calling +`DelayedStream.create()`. Modifying this property afterwards has no effect. + +### delayedStream.maxDataSize = 1024 * 1024 + +The amount of data to buffer before emitting an `error`. + +If the underlaying source is emitting `Buffer` objects, the `maxDataSize` +refers to bytes. + +If the underlaying source is emitting JavaScript strings, the size refers to +characters. + +If you know what you are doing, you can set this property to `Infinity` to +disable this feature. You can also modify this property during runtime. + +### delayedStream.maxDataSize = 1024 * 1024 + +The amount of data to buffer before emitting an `error`. + +If the underlaying source is emitting `Buffer` objects, the `maxDataSize` +refers to bytes. + +If the underlaying source is emitting JavaScript strings, the size refers to +characters. + +If you know what you are doing, you can set this property to `Infinity` to +disable this feature. + +### delayedStream.dataSize = 0 + +The amount of data buffered so far. + +### delayedStream.readable + +An ECMA5 getter that returns the value of `source.readable`. + +### delayedStream.resume() + +If the `delayedStream` has not been released so far, `delayedStream.release()` +is called. + +In either case, `source.resume()` is called. + +### delayedStream.pause() + +Calls `source.pause()`. + +### delayedStream.pipe(dest) + +Calls `delayedStream.resume()` and then proxies the arguments to `source.pipe`. + +### delayedStream.release() + +Emits and clears all events that have been buffered up so far. This does not +resume the underlaying source, use `delayedStream.resume()` instead. + +## License + +delayed-stream is licensed under the MIT license. diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js new file mode 100644 index 000000000..7c10d4825 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js @@ -0,0 +1,99 @@ +var Stream = require('stream').Stream; +var util = require('util'); + +module.exports = DelayedStream; +function DelayedStream() { + this.source = null; + this.dataSize = 0; + this.maxDataSize = 1024 * 1024; + this.pauseStream = true; + + this._maxDataSizeExceeded = false; + this._released = false; + this._bufferedEvents = []; +} +util.inherits(DelayedStream, Stream); + +DelayedStream.create = function(source, options) { + var delayedStream = new this(); + + options = options || {}; + for (var option in options) { + delayedStream[option] = options[option]; + } + + delayedStream.source = source; + + var realEmit = source.emit; + source.emit = function() { + delayedStream._handleEmit(arguments); + return realEmit.apply(source, arguments); + }; + + source.on('error', function() {}); + if (delayedStream.pauseStream) { + source.pause(); + } + + return delayedStream; +}; + +DelayedStream.prototype.__defineGetter__('readable', function() { + return this.source.readable; +}); + +DelayedStream.prototype.resume = function() { + if (!this._released) { + this.release(); + } + + this.source.resume(); +}; + +DelayedStream.prototype.pause = function() { + this.source.pause(); +}; + +DelayedStream.prototype.release = function() { + this._released = true; + + this._bufferedEvents.forEach(function(args) { + this.emit.apply(this, args); + }.bind(this)); + this._bufferedEvents = []; +}; + +DelayedStream.prototype.pipe = function() { + var r = Stream.prototype.pipe.apply(this, arguments); + this.resume(); + return r; +}; + +DelayedStream.prototype._handleEmit = function(args) { + if (this._released) { + this.emit.apply(this, args); + return; + } + + if (args[0] === 'data') { + this.dataSize += args[1].length; + this._checkIfMaxDataSizeExceeded(); + } + + this._bufferedEvents.push(args); +}; + +DelayedStream.prototype._checkIfMaxDataSizeExceeded = function() { + if (this._maxDataSizeExceeded) { + return; + } + + if (this.dataSize <= this.maxDataSize) { + return; + } + + this._maxDataSizeExceeded = true; + var message = + 'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.' + this.emit('error', new Error(message)); +}; diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/package.json b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/package.json new file mode 100644 index 000000000..6c2bb7707 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/package.json @@ -0,0 +1,32 @@ +{ + "author": { + "name": "Felix Geisendörfer", + "email": "felix@debuggable.com", + "url": "http://debuggable.com/" + }, + "name": "delayed-stream", + "description": "Buffers events from a stream until you are ready to handle them.", + "version": "0.0.5", + "homepage": "https://github.com/felixge/node-delayed-stream", + "repository": { + "type": "git", + "url": "git://github.com/felixge/node-delayed-stream.git" + }, + "main": "./lib/delayed_stream", + "engines": { + "node": ">=0.4.0" + }, + "dependencies": {}, + "devDependencies": { + "fake": "0.2.0", + "far": "0.0.1" + }, + "readme": "# delayed-stream\n\nBuffers events from a stream until you are ready to handle them.\n\n## Installation\n\n``` bash\nnpm install delayed-stream\n```\n\n## Usage\n\nThe following example shows how to write a http echo server that delays its\nresponse by 1000 ms.\n\n``` javascript\nvar DelayedStream = require('delayed-stream');\nvar http = require('http');\n\nhttp.createServer(function(req, res) {\n var delayed = DelayedStream.create(req);\n\n setTimeout(function() {\n res.writeHead(200);\n delayed.pipe(res);\n }, 1000);\n});\n```\n\nIf you are not using `Stream#pipe`, you can also manually release the buffered\nevents by calling `delayedStream.resume()`:\n\n``` javascript\nvar delayed = DelayedStream.create(req);\n\nsetTimeout(function() {\n // Emit all buffered events and resume underlaying source\n delayed.resume();\n}, 1000);\n```\n\n## Implementation\n\nIn order to use this meta stream properly, here are a few things you should\nknow about the implementation.\n\n### Event Buffering / Proxying\n\nAll events of the `source` stream are hijacked by overwriting the `source.emit`\nmethod. Until node implements a catch-all event listener, this is the only way.\n\nHowever, delayed-stream still continues to emit all events it captures on the\n`source`, regardless of whether you have released the delayed stream yet or\nnot.\n\nUpon creation, delayed-stream captures all `source` events and stores them in\nan internal event buffer. Once `delayedStream.release()` is called, all\nbuffered events are emitted on the `delayedStream`, and the event buffer is\ncleared. After that, delayed-stream merely acts as a proxy for the underlaying\nsource.\n\n### Error handling\n\nError events on `source` are buffered / proxied just like any other events.\nHowever, `delayedStream.create` attaches a no-op `'error'` listener to the\n`source`. This way you only have to handle errors on the `delayedStream`\nobject, rather than in two places.\n\n### Buffer limits\n\ndelayed-stream provides a `maxDataSize` property that can be used to limit\nthe amount of data being buffered. In order to protect you from bad `source`\nstreams that don't react to `source.pause()`, this feature is enabled by\ndefault.\n\n## API\n\n### DelayedStream.create(source, [options])\n\nReturns a new `delayedStream`. Available options are:\n\n* `pauseStream`\n* `maxDataSize`\n\nThe description for those properties can be found below.\n\n### delayedStream.source\n\nThe `source` stream managed by this object. This is useful if you are\npassing your `delayedStream` around, and you still want to access properties\non the `source` object.\n\n### delayedStream.pauseStream = true\n\nWhether to pause the underlaying `source` when calling\n`DelayedStream.create()`. Modifying this property afterwards has no effect.\n\n### delayedStream.maxDataSize = 1024 * 1024\n\nThe amount of data to buffer before emitting an `error`.\n\nIf the underlaying source is emitting `Buffer` objects, the `maxDataSize`\nrefers to bytes.\n\nIf the underlaying source is emitting JavaScript strings, the size refers to\ncharacters.\n\nIf you know what you are doing, you can set this property to `Infinity` to\ndisable this feature. You can also modify this property during runtime.\n\n### delayedStream.maxDataSize = 1024 * 1024\n\nThe amount of data to buffer before emitting an `error`.\n\nIf the underlaying source is emitting `Buffer` objects, the `maxDataSize`\nrefers to bytes.\n\nIf the underlaying source is emitting JavaScript strings, the size refers to\ncharacters.\n\nIf you know what you are doing, you can set this property to `Infinity` to\ndisable this feature.\n\n### delayedStream.dataSize = 0\n\nThe amount of data buffered so far.\n\n### delayedStream.readable\n\nAn ECMA5 getter that returns the value of `source.readable`.\n\n### delayedStream.resume()\n\nIf the `delayedStream` has not been released so far, `delayedStream.release()`\nis called.\n\nIn either case, `source.resume()` is called.\n\n### delayedStream.pause()\n\nCalls `source.pause()`.\n\n### delayedStream.pipe(dest)\n\nCalls `delayedStream.resume()` and then proxies the arguments to `source.pipe`.\n\n### delayedStream.release()\n\nEmits and clears all events that have been buffered up so far. This does not\nresume the underlaying source, use `delayedStream.resume()` instead.\n\n## License\n\ndelayed-stream is licensed under the MIT license.\n", + "readmeFilename": "Readme.md", + "_id": "delayed-stream@0.0.5", + "dist": { + "shasum": "052618e1471edc6f9affd1d89c0b0503c716f5a4" + }, + "_from": "delayed-stream@0.0.5", + "_resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz" +} diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/common.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/common.js new file mode 100644 index 000000000..4d71b8a64 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/common.js @@ -0,0 +1,6 @@ +var common = module.exports; + +common.DelayedStream = require('..'); +common.assert = require('assert'); +common.fake = require('fake'); +common.PORT = 49252; diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-http-upload.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-http-upload.js new file mode 100644 index 000000000..9ecad5b8a --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-http-upload.js @@ -0,0 +1,38 @@ +var common = require('../common'); +var assert = common.assert; +var DelayedStream = common.DelayedStream; +var http = require('http'); + +var UPLOAD = new Buffer(10 * 1024 * 1024); + +var server = http.createServer(function(req, res) { + var delayed = DelayedStream.create(req, {maxDataSize: UPLOAD.length}); + + setTimeout(function() { + res.writeHead(200); + delayed.pipe(res); + }, 10); +}); +server.listen(common.PORT, function() { + var request = http.request({ + method: 'POST', + port: common.PORT, + }); + + request.write(UPLOAD); + request.end(); + + request.on('response', function(res) { + var received = 0; + res + .on('data', function(chunk) { + received += chunk.length; + }) + .on('end', function() { + assert.equal(received, UPLOAD.length); + server.close(); + }); + }); +}); + + diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-auto-pause.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-auto-pause.js new file mode 100644 index 000000000..6f417f3e9 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-auto-pause.js @@ -0,0 +1,21 @@ +var common = require('../common'); +var assert = common.assert; +var fake = common.fake.create(); +var DelayedStream = common.DelayedStream; +var Stream = require('stream').Stream; + +(function testAutoPause() { + var source = new Stream(); + + fake.expect(source, 'pause', 1); + var delayedStream = DelayedStream.create(source); + fake.verify(); +})(); + +(function testDisableAutoPause() { + var source = new Stream(); + fake.expect(source, 'pause', 0); + + var delayedStream = DelayedStream.create(source, {pauseStream: false}); + fake.verify(); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-pause.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-pause.js new file mode 100644 index 000000000..b50c39783 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream-pause.js @@ -0,0 +1,14 @@ +var common = require('../common'); +var assert = common.assert; +var fake = common.fake.create(); +var DelayedStream = common.DelayedStream; +var Stream = require('stream').Stream; + +(function testDelayEventsUntilResume() { + var source = new Stream(); + var delayedStream = DelayedStream.create(source, {pauseStream: false}); + + fake.expect(source, 'pause'); + delayedStream.pause(); + fake.verify(); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream.js new file mode 100644 index 000000000..fc4047e08 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-delayed-stream.js @@ -0,0 +1,48 @@ +var common = require('../common'); +var assert = common.assert; +var fake = common.fake.create(); +var DelayedStream = common.DelayedStream; +var Stream = require('stream').Stream; + +(function testDelayEventsUntilResume() { + var source = new Stream(); + var delayedStream = DelayedStream.create(source, {pauseStream: false}); + + // delayedStream must not emit until we resume + fake.expect(delayedStream, 'emit', 0); + + // but our original source must emit + var params = []; + source.on('foo', function(param) { + params.push(param); + }); + + source.emit('foo', 1); + source.emit('foo', 2); + + // Make sure delayedStream did not emit, and source did + assert.deepEqual(params, [1, 2]); + fake.verify(); + + // After resume, delayedStream must playback all events + fake + .stub(delayedStream, 'emit') + .times(Infinity) + .withArg(1, 'newListener'); + fake.expect(delayedStream, 'emit', ['foo', 1]); + fake.expect(delayedStream, 'emit', ['foo', 2]); + fake.expect(source, 'resume'); + + delayedStream.resume(); + fake.verify(); + + // Calling resume again will delegate to source + fake.expect(source, 'resume'); + delayedStream.resume(); + fake.verify(); + + // Emitting more events directly leads to them being emitted + fake.expect(delayedStream, 'emit', ['foo', 3]); + source.emit('foo', 3); + fake.verify(); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-handle-source-errors.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-handle-source-errors.js new file mode 100644 index 000000000..a9d35e72c --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-handle-source-errors.js @@ -0,0 +1,15 @@ +var common = require('../common'); +var assert = common.assert; +var fake = common.fake.create(); +var DelayedStream = common.DelayedStream; +var Stream = require('stream').Stream; + +(function testHandleSourceErrors() { + var source = new Stream(); + var delayedStream = DelayedStream.create(source, {pauseStream: false}); + + // We deal with this by attaching a no-op listener to 'error' on the source + // when creating a new DelayedStream. This way error events on the source + // won't throw. + source.emit('error', new Error('something went wrong')); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-max-data-size.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-max-data-size.js new file mode 100644 index 000000000..7638a2bf0 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-max-data-size.js @@ -0,0 +1,18 @@ +var common = require('../common'); +var assert = common.assert; +var fake = common.fake.create(); +var DelayedStream = common.DelayedStream; +var Stream = require('stream').Stream; + +(function testMaxDataSize() { + var source = new Stream(); + var delayedStream = DelayedStream.create(source, {maxDataSize: 1024, pauseStream: false}); + + source.emit('data', new Buffer(1024)); + + fake + .expect(delayedStream, 'emit') + .withArg(1, 'error'); + source.emit('data', new Buffer(1)); + fake.verify(); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-pipe-resumes.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-pipe-resumes.js new file mode 100644 index 000000000..7d312ab1f --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-pipe-resumes.js @@ -0,0 +1,13 @@ +var common = require('../common'); +var assert = common.assert; +var fake = common.fake.create(); +var DelayedStream = common.DelayedStream; +var Stream = require('stream').Stream; + +(function testPipeReleases() { + var source = new Stream(); + var delayedStream = DelayedStream.create(source, {pauseStream: false}); + + fake.expect(delayedStream, 'resume'); + delayedStream.pipe(new Stream()); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-proxy-readable.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-proxy-readable.js new file mode 100644 index 000000000..d436163b7 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/integration/test-proxy-readable.js @@ -0,0 +1,13 @@ +var common = require('../common'); +var assert = common.assert; +var fake = common.fake.create(); +var DelayedStream = common.DelayedStream; +var Stream = require('stream').Stream; + +(function testProxyReadableProperty() { + var source = new Stream(); + var delayedStream = DelayedStream.create(source, {pauseStream: false}); + + source.readable = fake.value('source.readable'); + assert.strictEqual(delayedStream.readable, source.readable); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/run.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/run.js new file mode 100755 index 000000000..0bb8e8224 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/test/run.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var far = require('far').create(); + +far.add(__dirname); +far.include(/test-.*\.js$/); + +far.execute(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/package.json b/node_modules/request/node_modules/form-data/node_modules/combined-stream/package.json new file mode 100644 index 000000000..5f1328650 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/package.json @@ -0,0 +1,33 @@ +{ + "author": { + "name": "Felix Geisendörfer", + "email": "felix@debuggable.com", + "url": "http://debuggable.com/" + }, + "name": "combined-stream", + "description": "A stream that emits multiple other streams one after another.", + "version": "0.0.4", + "homepage": "https://github.com/felixge/node-combined-stream", + "repository": { + "type": "git", + "url": "git://github.com/felixge/node-combined-stream.git" + }, + "main": "./lib/combined_stream", + "engines": { + "node": "*" + }, + "dependencies": { + "delayed-stream": "0.0.5" + }, + "devDependencies": { + "far": "0.0.1" + }, + "readme": "# combined-stream\n\nA stream that emits multiple other streams one after another.\n\n## Installation\n\n``` bash\nnpm install combined-stream\n```\n\n## Usage\n\nHere is a simple example that shows how you can use combined-stream to combine\ntwo files into one:\n\n``` javascript\nvar CombinedStream = require('combined-stream');\nvar fs = require('fs');\n\nvar combinedStream = CombinedStream.create();\ncombinedStream.append(fs.createReadStream('file1.txt'));\ncombinedStream.append(fs.createReadStream('file2.txt'));\n\ncombinedStream.pipe(fs.createWriteStream('combined.txt'));\n```\n\nWhile the example above works great, it will pause all source streams until\nthey are needed. If you don't want that to happen, you can set `pauseStreams`\nto `false`:\n\n``` javascript\nvar CombinedStream = require('combined-stream');\nvar fs = require('fs');\n\nvar combinedStream = CombinedStream.create({pauseStreams: false});\ncombinedStream.append(fs.createReadStream('file1.txt'));\ncombinedStream.append(fs.createReadStream('file2.txt'));\n\ncombinedStream.pipe(fs.createWriteStream('combined.txt'));\n```\n\nHowever, what if you don't have all the source streams yet, or you don't want\nto allocate the resources (file descriptors, memory, etc.) for them right away?\nWell, in that case you can simply provide a callback that supplies the stream\nby calling a `next()` function:\n\n``` javascript\nvar CombinedStream = require('combined-stream');\nvar fs = require('fs');\n\nvar combinedStream = CombinedStream.create();\ncombinedStream.append(function(next) {\n next(fs.createReadStream('file1.txt'));\n});\ncombinedStream.append(function(next) {\n next(fs.createReadStream('file2.txt'));\n});\n\ncombinedStream.pipe(fs.createWriteStream('combined.txt'));\n```\n\n## API\n\n### CombinedStream.create([options])\n\nReturns a new combined stream object. Available options are:\n\n* `maxDataSize`\n* `pauseStreams`\n\nThe effect of those options is described below.\n\n### combinedStream.pauseStreams = true\n\nWhether to apply back pressure to the underlaying streams. If set to `false`,\nthe underlaying streams will never be paused. If set to `true`, the\nunderlaying streams will be paused right after being appended, as well as when\n`delayedStream.pipe()` wants to throttle.\n\n### combinedStream.maxDataSize = 2 * 1024 * 1024\n\nThe maximum amount of bytes (or characters) to buffer for all source streams.\nIf this value is exceeded, `combinedStream` emits an `'error'` event.\n\n### combinedStream.dataSize = 0\n\nThe amount of bytes (or characters) currently buffered by `combinedStream`.\n\n### combinedStream.append(stream)\n\nAppends the given `stream` to the combinedStream object. If `pauseStreams` is\nset to `true, this stream will also be paused right away.\n\n`streams` can also be a function that takes one parameter called `next`. `next`\nis a function that must be invoked in order to provide the `next` stream, see\nexample above.\n\nRegardless of how the `stream` is appended, combined-stream always attaches an\n`'error'` listener to it, so you don't have to do that manually.\n\nSpecial case: `stream` can also be a String or Buffer.\n\n### combinedStream.write(data)\n\nYou should not call this, `combinedStream` takes care of piping the appended\nstreams into itself for you.\n\n### combinedStream.resume()\n\nCauses `combinedStream` to start drain the streams it manages. The function is\nidempotent, and also emits a `'resume'` event each time which usually goes to\nthe stream that is currently being drained.\n\n### combinedStream.pause();\n\nIf `combinedStream.pauseStreams` is set to `false`, this does nothing.\nOtherwise a `'pause'` event is emitted, this goes to the stream that is\ncurrently being drained, so you can use it to apply back pressure.\n\n### combinedStream.end();\n\nSets `combinedStream.writable` to false, emits an `'end'` event, and removes\nall streams from the queue.\n\n### combinedStream.destroy();\n\nSame as `combinedStream.end()`, except it emits a `'close'` event instead of\n`'end'`.\n\n## License\n\ncombined-stream is licensed under the MIT license.\n", + "readmeFilename": "Readme.md", + "_id": "combined-stream@0.0.4", + "dist": { + "shasum": "818920f2e68d41ae5fac5f154dfbed98b675d34f" + }, + "_from": "combined-stream@~0.0.4", + "_resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.4.tgz" +} diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/common.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/common.js new file mode 100644 index 000000000..81543485e --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/common.js @@ -0,0 +1,23 @@ +var common = module.exports; + +var path = require('path'); +var fs = require('fs'); +var root = path.join(__dirname, '..'); + +common.dir = { + fixture: root + '/test/fixture', + tmp: root + '/test/tmp', +}; + +// Create tmp directory if it does not exist +// Not using fs.exists so as to be node 0.6.x compatible +try { + fs.statSync(common.dir.tmp); +} +catch (e) { + // Dir does not exist + fs.mkdirSync(common.dir.tmp); +} + +common.CombinedStream = require(root); +common.assert = require('assert'); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file1.txt b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file1.txt new file mode 100644 index 000000000..50e0218df --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file1.txt @@ -0,0 +1,256 @@ +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 +10101010101010101010101010101010101010101010101010101010101010101010101010101010 +01010101010101010101010101010101010101010101010101010101010101010101010101010101 diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file2.txt b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file2.txt new file mode 100644 index 000000000..da1d821fe --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/fixture/file2.txt @@ -0,0 +1,256 @@ +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 +20202020202020202020202020202020202020202020202020202020202020202020202020202020 +02020202020202020202020202020202020202020202020202020202020202020202020202020202 diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-callback-streams.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-callback-streams.js new file mode 100644 index 000000000..44ecabab6 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-callback-streams.js @@ -0,0 +1,27 @@ +var common = require('../common'); +var assert = common.assert; +var CombinedStream = common.CombinedStream; +var fs = require('fs'); + +var FILE1 = common.dir.fixture + '/file1.txt'; +var FILE2 = common.dir.fixture + '/file2.txt'; +var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2); + +(function testDelayedStreams() { + var combinedStream = CombinedStream.create(); + combinedStream.append(function(next) { + next(fs.createReadStream(FILE1)); + }); + combinedStream.append(function(next) { + next(fs.createReadStream(FILE2)); + }); + + var tmpFile = common.dir.tmp + '/combined.txt'; + var dest = fs.createWriteStream(tmpFile); + combinedStream.pipe(dest); + + dest.on('end', function() { + var written = fs.readFileSync(tmpFile, 'utf8'); + assert.strictEqual(written, EXPECTED); + }); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-data-size.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-data-size.js new file mode 100644 index 000000000..e3fbd1842 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-data-size.js @@ -0,0 +1,34 @@ +var common = require('../common'); +var assert = common.assert; +var CombinedStream = common.CombinedStream; + +(function testDataSizeGetter() { + var combinedStream = CombinedStream.create(); + + assert.strictEqual(combinedStream.dataSize, 0); + + // Test one stream + combinedStream._streams.push({dataSize: 10}); + combinedStream._updateDataSize(); + assert.strictEqual(combinedStream.dataSize, 10); + + // Test two streams + combinedStream._streams.push({dataSize: 23}); + combinedStream._updateDataSize(); + assert.strictEqual(combinedStream.dataSize, 33); + + // Test currentStream + combinedStream._currentStream = {dataSize: 20}; + combinedStream._updateDataSize(); + assert.strictEqual(combinedStream.dataSize, 53); + + // Test currentStream without dataSize + combinedStream._currentStream = {}; + combinedStream._updateDataSize(); + assert.strictEqual(combinedStream.dataSize, 33); + + // Test stream function + combinedStream._streams.push(function() {}); + combinedStream._updateDataSize(); + assert.strictEqual(combinedStream.dataSize, 33); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams-and-buffers-and-strings.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams-and-buffers-and-strings.js new file mode 100644 index 000000000..c678575c0 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams-and-buffers-and-strings.js @@ -0,0 +1,38 @@ +var common = require('../common'); +var assert = common.assert; +var CombinedStream = common.CombinedStream; +var fs = require('fs'); + +var FILE1 = common.dir.fixture + '/file1.txt'; +var BUFFER = new Buffer('Bacon is delicious'); +var FILE2 = common.dir.fixture + '/file2.txt'; +var STRING = 'The € kicks the $\'s ass!'; + +var EXPECTED = + fs.readFileSync(FILE1) + + BUFFER + + fs.readFileSync(FILE2) + + STRING; +var GOT; + +(function testDelayedStreams() { + var combinedStream = CombinedStream.create(); + combinedStream.append(fs.createReadStream(FILE1)); + combinedStream.append(BUFFER); + combinedStream.append(fs.createReadStream(FILE2)); + combinedStream.append(function(next) { + next(STRING); + }); + + var tmpFile = common.dir.tmp + '/combined-file1-buffer-file2-string.txt'; + var dest = fs.createWriteStream(tmpFile); + combinedStream.pipe(dest); + + dest.on('close', function() { + GOT = fs.readFileSync(tmpFile, 'utf8'); + }); +})(); + +process.on('exit', function() { + assert.strictEqual(GOT, EXPECTED); +}); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams.js new file mode 100644 index 000000000..263cfdf72 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-delayed-streams.js @@ -0,0 +1,35 @@ +var common = require('../common'); +var assert = common.assert; +var CombinedStream = common.CombinedStream; +var fs = require('fs'); + +var FILE1 = common.dir.fixture + '/file1.txt'; +var FILE2 = common.dir.fixture + '/file2.txt'; +var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2); +var GOT; + +(function testDelayedStreams() { + var combinedStream = CombinedStream.create(); + combinedStream.append(fs.createReadStream(FILE1)); + combinedStream.append(fs.createReadStream(FILE2)); + + var stream1 = combinedStream._streams[0]; + var stream2 = combinedStream._streams[1]; + + stream1.on('end', function() { + assert.equal(stream2.dataSize, 0); + }); + + var tmpFile = common.dir.tmp + '/combined.txt'; + var dest = fs.createWriteStream(tmpFile); + combinedStream.pipe(dest); + + dest.on('close', function() { + GOT = fs.readFileSync(tmpFile, 'utf8'); + }); +})(); + +process.on('exit', function() { + console.error(GOT.length, EXPECTED.length); + assert.strictEqual(GOT, EXPECTED); +}); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-empty-string.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-empty-string.js new file mode 100644 index 000000000..c3d288d01 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-empty-string.js @@ -0,0 +1,39 @@ +var common = require('../common'); +var assert = common.assert; +var CombinedStream = common.CombinedStream; +var util = require('util'); +var Stream = require('stream').Stream; + +var s = CombinedStream.create(); + + +function StringStream(){ + this.writable=true; + this.str="" +} +util.inherits(StringStream,Stream); + +StringStream.prototype.write=function(chunk,encoding){ + this.str+=chunk.toString(); + this.emit('data',chunk); +} + +StringStream.prototype.end=function(chunk,encoding){ + this.emit('end'); +} + +StringStream.prototype.toString=function(){ + return this.str; +} + + +s.append("foo."); +s.append(""); +s.append("bar"); + +var ss = new StringStream(); + +s.pipe(ss); +s.resume(); + +assert.equal(ss.toString(),"foo.bar"); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-is-stream-like.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-is-stream-like.js new file mode 100644 index 000000000..aefa36e6b --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-is-stream-like.js @@ -0,0 +1,17 @@ +var fs = require('fs'); +var common = require('../common'); +var assert = common.assert; +var CombinedStream = common.CombinedStream; +var FILE1 = common.dir.fixture + '/file1.txt'; +var fileStream = fs.createReadStream(FILE1); + +var foo = function(){}; + +(function testIsStreamLike() { + assert(! CombinedStream.isStreamLike(true)); + assert(! CombinedStream.isStreamLike("I am a string")); + assert(! CombinedStream.isStreamLike(7)); + assert(! CombinedStream.isStreamLike(foo)); + + assert(CombinedStream.isStreamLike(fileStream)); +})();
\ No newline at end of file diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-max-data-size.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-max-data-size.js new file mode 100644 index 000000000..25f47a47c --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-max-data-size.js @@ -0,0 +1,24 @@ +var common = require('../common'); +var assert = common.assert; +var CombinedStream = common.CombinedStream; +var fs = require('fs'); + +var FILE1 = common.dir.fixture + '/file1.txt'; +var FILE2 = common.dir.fixture + '/file2.txt'; +var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2); + +(function testDelayedStreams() { + var combinedStream = CombinedStream.create({pauseStreams: false, maxDataSize: 20736}); + combinedStream.append(fs.createReadStream(FILE1)); + combinedStream.append(fs.createReadStream(FILE2)); + + var gotErr = null; + combinedStream.on('error', function(err) { + gotErr = err; + }); + + process.on('exit', function() { + assert.ok(gotErr); + assert.ok(gotErr.message.match(/bytes/)); + }); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-unpaused-streams.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-unpaused-streams.js new file mode 100644 index 000000000..30a3a6f84 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/integration/test-unpaused-streams.js @@ -0,0 +1,30 @@ +var common = require('../common'); +var assert = common.assert; +var CombinedStream = common.CombinedStream; +var fs = require('fs'); + +var FILE1 = common.dir.fixture + '/file1.txt'; +var FILE2 = common.dir.fixture + '/file2.txt'; +var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2); + +(function testDelayedStreams() { + var combinedStream = CombinedStream.create({pauseStreams: false}); + combinedStream.append(fs.createReadStream(FILE1)); + combinedStream.append(fs.createReadStream(FILE2)); + + var stream1 = combinedStream._streams[0]; + var stream2 = combinedStream._streams[1]; + + stream1.on('end', function() { + assert.ok(stream2.dataSize > 0); + }); + + var tmpFile = common.dir.tmp + '/combined.txt'; + var dest = fs.createWriteStream(tmpFile); + combinedStream.pipe(dest); + + dest.on('end', function() { + var written = fs.readFileSync(tmpFile, 'utf8'); + assert.strictEqual(written, EXPECTED); + }); +})(); diff --git a/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/run.js b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/run.js new file mode 100755 index 000000000..0bb8e8224 --- /dev/null +++ b/node_modules/request/node_modules/form-data/node_modules/combined-stream/test/run.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var far = require('far').create(); + +far.add(__dirname); +far.include(/test-.*\.js$/); + +far.execute(); diff --git a/node_modules/request/node_modules/form-data/package.json b/node_modules/request/node_modules/form-data/package.json new file mode 100644 index 000000000..2f42e8d93 --- /dev/null +++ b/node_modules/request/node_modules/form-data/package.json @@ -0,0 +1,37 @@ +{ + "author": { + "name": "Felix Geisendörfer", + "email": "felix@debuggable.com", + "url": "http://debuggable.com/" + }, + "name": "form-data", + "description": "A module to create readable `\"multipart/form-data\"` streams. Can be used to submit forms and file uploads to other web applications.", + "version": "0.0.7", + "repository": { + "type": "git", + "url": "git://github.com/felixge/node-form-data.git" + }, + "main": "./lib/form_data", + "engines": { + "node": "*" + }, + "dependencies": { + "combined-stream": "~0.0.4", + "mime": "~1.2.2", + "async": "~0.1.9" + }, + "devDependencies": { + "fake": "0.2.1", + "far": "0.0.1", + "formidable": "1.0.2", + "request": "~2.9.203" + }, + "readme": "# form-data\n\nA module to create readable `\"multipart/form-data\"` streams. Can be used to\nsubmit forms and file uploads to other web applications.\n\nThe API of this module is inspired by the\n[XMLHttpRequest-2 FormData Interface][xhr2-fd].\n\n[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface\n\n## Install\n\nSorry, this isn't ready for you yet.\n\n## Usage\n\nIn this example we are constructing a form with 3 fields that contain a string,\na buffer and a file stream.\n\n``` javascript\nvar FormData = require('form-data');\nvar fs = require('fs');\n\nvar form = new FormData();\nform.append('my_field', 'my value');\nform.append('my_buffer', new Buffer(10));\nform.append('my_file', fs.createReadStream('/foo/bar.jpg'));\n```\n\nAlso you can use http-response stream:\n\n``` javascript\nvar FormData = require('form-data');\nvar http = require('http');\n\nvar form = new FormData();\n\nhttp.request('http://nodejs.org/images/logo.png', function(response) {\n form.append('my_field', 'my value');\n form.append('my_buffer', new Buffer(10));\n form.append('my_logo', response);\n});\n```\n\nOr @mikeal's request stream:\n\n``` javascript\nvar FormData = require('form-data');\nvar request = require('request');\n\nvar form = new FormData();\n\nform.append('my_field', 'my value');\nform.append('my_buffer', new Buffer(10));\nform.append('my_logo', request('http://nodejs.org/images/logo.png'));\n```\n\nIn order to submit this form to a web application, you can use node's http\nclient interface:\n\n``` javascript\nvar http = require('http');\n\nvar request = http.request({\n method: 'post',\n host: 'example.org',\n path: '/upload',\n headers: form.getHeaders()\n});\n\nform.pipe(request);\n\nrequest.on('response', function(res) {\n console.log(res.statusCode);\n});\n```\n\nOr if you would prefer the `'Content-Length'` header to be set for you:\n\n``` javascript\nform.submit('example.org/upload', function(err, res) {\n console.log(res.statusCode);\n});\n```\n\nTo use custom headers and pre-known length in parts:\n\n``` javascript\nvar CRLF = '\\r\\n';\nvar form = new FormData();\n\nvar options = {\n header: CRLF + '--' + form.getBoundary() + CRLF + 'X-Custom-Header: 123' + CRLF + CRLF,\n knownLength: 1\n};\n\nform.append('my_buffer', buffer, options);\n\nform.submit('http://example.com/', function(err, res) {\n if (err) throw err;\n console.log('Done');\n});\n```\n\nFor edge cases, like POST request to URL with query string or to pass HTTP auth creadentials, object can be passed to `form.submit()` as first parameter:\n\n``` javascript\nform.submit({\n host: 'example.com',\n path: '/probably.php?extra=params',\n auth: 'username:password'\n}, function(err, res) {\n console.log(res.statusCode);\n});\n```\n\n\n[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface\n", + "readmeFilename": "Readme.md", + "_id": "form-data@0.0.7", + "dist": { + "shasum": "aaa2ad518b0755c0aab584ae7e1c34f6cc8b57fd" + }, + "_from": "form-data@~0.0.3", + "_resolved": "https://registry.npmjs.org/form-data/-/form-data-0.0.7.tgz" +} diff --git a/node_modules/request/node_modules/form-data/test/common.js b/node_modules/request/node_modules/form-data/test/common.js new file mode 100644 index 000000000..8a26482e1 --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/common.js @@ -0,0 +1,14 @@ +var common = module.exports; +var path = require('path'); + +var rootDir = path.join(__dirname, '..'); +common.dir = { + lib: rootDir + '/lib', + fixture: rootDir + '/test/fixture', + tmp: rootDir + '/test/tmp', +}; + +common.assert = require('assert'); +common.fake = require('fake'); + +common.port = 8432; diff --git a/node_modules/request/node_modules/form-data/test/fixture/bacon.txt b/node_modules/request/node_modules/form-data/test/fixture/bacon.txt new file mode 100644 index 000000000..9804bbdc6 --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/fixture/bacon.txt @@ -0,0 +1 @@ +Bacon is delicious. diff --git a/node_modules/request/node_modules/form-data/test/fixture/unicycle.jpg b/node_modules/request/node_modules/form-data/test/fixture/unicycle.jpg Binary files differnew file mode 100644 index 000000000..7cea4dd71 --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/fixture/unicycle.jpg diff --git a/node_modules/request/node_modules/form-data/test/integration/test-custom-headers.js b/node_modules/request/node_modules/form-data/test/integration/test-custom-headers.js new file mode 100644 index 000000000..1c9b6adad --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/integration/test-custom-headers.js @@ -0,0 +1,75 @@ +/* +test custom headers, added in pull request: +https://github.com/felixge/node-form-data/pull/17 +*/ + +var common = require('../common'); +var assert = common.assert; +var http = require('http'); + +var FormData = require(common.dir.lib + '/form_data'); + +var CRLF = '\r\n'; + +var testHeader = 'X-Test-Fake: 123'; + +var expectedLength; + + +var server = http.createServer(function(req, res) { + var data = ''; + req.setEncoding('utf8'); + + req.on('data', function(d) { + data += d; + }); + + req.on('end', function() { + assert.ok( data.indexOf( testHeader ) != -1 ); + + // content-length would be 1000+ w/actual buffer size, + // but smaller w/overridden size. + assert.ok( typeof req.headers['content-length'] !== 'undefined' ); + assert.equal(req.headers['content-length'], expectedLength); + + res.writeHead(200); + res.end('done'); + }); +}); + + +server.listen(common.port, function() { + var form = new FormData(); + + var options = { + header: + CRLF + '--' + form.getBoundary() + CRLF + + testHeader + + CRLF + CRLF, + + // override content-length, + // much lower than actual buffer size (1000) + knownLength: 1 + }; + + var bufferData = []; + for (var z = 0; z < 1000; z++) { + bufferData.push(1); + } + var buffer = new Buffer(bufferData); + + form.append('my_buffer', buffer, options); + + // (available to req handler) + expectedLength = form._lastBoundary().length + form._overheadLength + options.knownLength; + + form.submit('http://localhost:' + common.port + '/', function(err, res) { + if (err) { + throw err; + } + + assert.strictEqual(res.statusCode, 200); + server.close(); + }); + +}); diff --git a/node_modules/request/node_modules/form-data/test/integration/test-form-get-length.js b/node_modules/request/node_modules/form-data/test/integration/test-form-get-length.js new file mode 100644 index 000000000..44d3b4dc2 --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/integration/test-form-get-length.js @@ -0,0 +1,93 @@ +var common = require('../common'); +var assert = common.assert; +var FormData = require(common.dir.lib + '/form_data'); +var fake = require('fake').create(); +var fs = require('fs'); + +(function testEmptyForm() { + var form = new FormData(); + var callback = fake.callback(arguments.callee.name + '-getLength'); + var calls = fake.expectAnytime(callback, [null, 0]).calls; + + form.getLength(callback); + + // Make sure our response is async + assert.strictEqual(calls.length, 0); +})(); + +(function testUtf8String() { + var FIELD = 'my_field'; + var VALUE = 'May the € be with you'; + + var form = new FormData(); + form.append(FIELD, VALUE); + var callback = fake.callback(arguments.callee.name + '-getLength'); + + var expectedLength = + form._overheadLength + + Buffer.byteLength(VALUE) + + form._lastBoundary().length; + + fake.expectAnytime(callback, [null, expectedLength]); + form.getLength(callback); +})(); + +(function testBuffer() { + var FIELD = 'my_field'; + var VALUE = new Buffer(23); + + var form = new FormData(); + form.append(FIELD, VALUE); + var callback = fake.callback(arguments.callee.name + '-getLength'); + + var expectedLength = + form._overheadLength + + VALUE.length + + form._lastBoundary().length; + + fake.expectAnytime(callback, [null, expectedLength]); + form.getLength(callback); +})(); + + +(function testStringFileBufferFile() { + var fields = [ + { + name: 'my_field', + value: 'Test 123', + }, + { + name: 'my_image', + value: fs.createReadStream(common.dir.fixture + '/unicycle.jpg'), + }, + { + name: 'my_buffer', + value: new Buffer('123'), + }, + { + name: 'my_txt', + value: fs.createReadStream(common.dir.fixture + '/bacon.txt'), + }, + ]; + + var form = new FormData(); + var expectedLength = 0; + + fields.forEach(function(field) { + form.append(field.name, field.value); + if (field.value.path) { + var stat = fs.statSync(field.value.path); + expectedLength += stat.size; + } else { + expectedLength += field.value.length; + } + }); + + expectedLength += form._overheadLength + form._lastBoundary().length; + + var callback = fake.callback(arguments.callee.name + '-getLength'); + fake.expectAnytime(callback, [null, expectedLength]); + form.getLength(callback); +})(); + + diff --git a/node_modules/request/node_modules/form-data/test/integration/test-get-boundary.js b/node_modules/request/node_modules/form-data/test/integration/test-get-boundary.js new file mode 100644 index 000000000..6dc2fb2bd --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/integration/test-get-boundary.js @@ -0,0 +1,18 @@ +var common = require('../common'); +var assert = common.assert; + +var FormData = require(common.dir.lib + '/form_data'); + +(function testOneBoundaryPerForm() { + var form = new FormData(); + var boundary = form.getBoundary(); + + assert.equal(boundary, form.getBoundary()); + assert.equal(boundary.length, 50); +})(); + +(function testUniqueBoundaryPerForm() { + var formA = new FormData(); + var formB = new FormData(); + assert.notEqual(formA.getBoundary(), formB.getBoundary()); +})(); diff --git a/node_modules/request/node_modules/form-data/test/integration/test-http-response.js b/node_modules/request/node_modules/form-data/test/integration/test-http-response.js new file mode 100644 index 000000000..8e183fed3 --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/integration/test-http-response.js @@ -0,0 +1,121 @@ +var common = require('../common'); +var assert = common.assert; +var http = require('http'); +var path = require('path'); +var mime = require('mime'); +var request = require('request'); +var parseUrl = require('url').parse; +var fs = require('fs'); +var FormData = require(common.dir.lib + '/form_data'); +var IncomingForm = require('formidable').IncomingForm; + +var remoteFile = 'http://nodejs.org/images/logo.png'; + +var FIELDS; +var server; + +var parsedUrl = parseUrl(remoteFile) + , options = { + method: 'get', + port: parsedUrl.port || 80, + path: parsedUrl.pathname, + host: parsedUrl.hostname + } + ; + +http.request(options, function(res) { + + FIELDS = [ + {name: 'my_field', value: 'my_value'}, + {name: 'my_buffer', value: new Buffer([1, 2, 3])}, + {name: 'remote_file', value: res } + ]; + + var form = new FormData(); + FIELDS.forEach(function(field) { + form.append(field.name, field.value); + }); + + server.listen(common.port, function() { + + form.submit('http://localhost:' + common.port + '/', function(err, res) { + + if (err) { + throw err; + } + + assert.strictEqual(res.statusCode, 200); + server.close(); + }); + + }); + + +}).end(); + +server = http.createServer(function(req, res) { + + // formidable is broken so let's do it manual way + // + // var form = new IncomingForm(); + // form.uploadDir = common.dir.tmp; + // form.parse(req); + // form + // .on('field', function(name, value) { + // var field = FIELDS.shift(); + // assert.strictEqual(name, field.name); + // assert.strictEqual(value, field.value+''); + // }) + // .on('file', function(name, file) { + // var field = FIELDS.shift(); + // assert.strictEqual(name, field.name); + // assert.strictEqual(file.name, path.basename(field.value.path)); + // // mime.lookup file.NAME == 'my_file' ? + // assert.strictEqual(file.type, mime.lookup(file.name)); + // }) + // .on('end', function() { + // res.writeHead(200); + // res.end('done'); + // }); + + // temp workaround + var data = ''; + req.setEncoding('utf8'); + + req.on('data', function(d) { + data += d; + }); + + req.on('end', function() { + + // check for the fields' traces + + // 1st field : my_field + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 2nd field : my_buffer + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 3rd field : remote_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(remoteFile)+'"') != -1 ); + // check for http://nodejs.org/images/logo.png traces + assert.ok( data.indexOf('ImageReady') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(remoteFile) ) != -1 ); + + res.writeHead(200); + res.end('done'); + + }); + +}); + + +process.on('exit', function() { + assert.strictEqual(FIELDS.length, 0); +}); diff --git a/node_modules/request/node_modules/form-data/test/integration/test-pipe.js b/node_modules/request/node_modules/form-data/test/integration/test-pipe.js new file mode 100644 index 000000000..3cb4ce44a --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/integration/test-pipe.js @@ -0,0 +1,120 @@ +var common = require('../common'); +var assert = common.assert; +var http = require('http'); +var path = require('path'); +var mime = require('mime'); +var request = require('request'); +var fs = require('fs'); +var FormData = require(common.dir.lib + '/form_data'); +var IncomingForm = require('formidable').IncomingForm; + +var remoteFile = 'http://nodejs.org/images/logo.png'; + +// wrap non simple values into function +// just to deal with ReadStream "autostart" +// Can't wait for 0.10 +var FIELDS = [ + {name: 'my_field', value: 'my_value'}, + {name: 'my_buffer', value: function(){ return new Buffer([1, 2, 3])} }, + {name: 'my_file', value: function(){ return fs.createReadStream(common.dir.fixture + '/unicycle.jpg')} }, + {name: 'remote_file', value: function(){ return request(remoteFile)} } +]; + +var server = http.createServer(function(req, res) { + + // formidable is fixed on github + // but still 7 month old in npm + // + // var form = new IncomingForm(); + // form.uploadDir = common.dir.tmp; + // form.parse(req); + // form + // .on('field', function(name, value) { + // var field = FIELDS.shift(); + // assert.strictEqual(name, field.name); + // assert.strictEqual(value, field.value+''); + // }) + // .on('file', function(name, file) { + // var field = FIELDS.shift(); + // assert.strictEqual(name, field.name); + // assert.strictEqual(file.name, path.basename(field.value.path)); + // assert.strictEqual(file.type, mime.lookup(file.name)); + // }) + // .on('end', function() { + // res.writeHead(200); + // res.end('done'); + // }); + + // temp workaround + var data = ''; + req.setEncoding('utf8'); + + req.on('data', function(d) { + data += d; + }); + + req.on('end', function() { + // check for the fields' traces + + // 1st field : my_field + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 2nd field : my_buffer + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 3rd field : my_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 ); + + // check for unicycle.jpg traces + assert.ok( data.indexOf('2005:06:21 01:44:12') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(field.value.path) ) != -1 ); + + // 4th field : remote_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 ); + // check for http://nodejs.org/images/logo.png traces + assert.ok( data.indexOf('ImageReady') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(remoteFile) ) != -1 ); + + res.writeHead(200); + res.end('done'); + + }); + + +}); + +server.listen(common.port, function() { + var form = new FormData(); + FIELDS.forEach(function(field) { + // important to append ReadStreams within the same tick + if ((typeof field.value == 'function')) { + field.value = field.value(); + } + form.append(field.name, field.value); + }); + + var request = http.request({ + method: 'post', + port: common.port, + path: '/upload', + headers: form.getHeaders() + }); + + form.pipe(request); + + request.on('response', function(res) { + server.close(); + }); +}); + +process.on('exit', function() { + assert.strictEqual(FIELDS.length, 0); +}); diff --git a/node_modules/request/node_modules/form-data/test/integration/test-submit-custom.js b/node_modules/request/node_modules/form-data/test/integration/test-submit-custom.js new file mode 100644 index 000000000..0e4c592e7 --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/integration/test-submit-custom.js @@ -0,0 +1,121 @@ +var common = require('../common'); +var assert = common.assert; +var http = require('http'); +var path = require('path'); +var mime = require('mime'); +var request = require('request'); +var fs = require('fs'); +var FormData = require(common.dir.lib + '/form_data'); +var IncomingForm = require('formidable').IncomingForm; + +var remoteFile = 'http://nodejs.org/images/logo.png'; + +// wrap non simple values into function +// just to deal with ReadStream "autostart" +// Can't wait for 0.10 +var FIELDS = [ + {name: 'my_field', value: 'my_value'}, + {name: 'my_buffer', value: function(){ return new Buffer([1, 2, 3])} }, + {name: 'my_file', value: function(){ return fs.createReadStream(common.dir.fixture + '/unicycle.jpg')} }, + {name: 'remote_file', value: function(){ return request(remoteFile)} } +]; + +var server = http.createServer(function(req, res) { + + // formidable is fixed on github + // but still 7 month old in npm + // + // var form = new IncomingForm(); + // form.uploadDir = common.dir.tmp; + // form.parse(req); + // form + // .on('field', function(name, value) { + // var field = FIELDS.shift(); + // assert.strictEqual(name, field.name); + // assert.strictEqual(value, field.value+''); + // }) + // .on('file', function(name, file) { + // var field = FIELDS.shift(); + // assert.strictEqual(name, field.name); + // assert.strictEqual(file.name, path.basename(field.value.path)); + // // mime.lookup file.NAME == 'my_file' ? + // assert.strictEqual(file.type, mime.lookup(file.name)); + // }) + // .on('end', function() { + // res.writeHead(200); + // res.end('done'); + // }); + + // temp workaround + var data = ''; + req.setEncoding('utf8'); + req.on('data', function(d) { + data += d; + }); + req.on('end', function() { + // check for the fields' traces + + // 1st field : my_field + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 2nd field : my_buffer + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 3rd field : my_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 ); + // check for unicycle.jpg traces + assert.ok( data.indexOf('2005:06:21 01:44:12') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(field.value.path) ) != -1 ); + + // 4th field : remote_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 ); + // check for http://nodejs.org/images/logo.png traces + assert.ok( data.indexOf('ImageReady') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(remoteFile) ) != -1 ); + + res.writeHead(200); + res.end('done'); + + }); + +}); + +server.listen(common.port, function() { + + var form = new FormData(); + + FIELDS.forEach(function(field) { + // important to append ReadStreams within the same tick + if ((typeof field.value == 'function')) { + field.value = field.value(); + } + form.append(field.name, field.value); + }); + + // custom params object passed to submit + form.submit({ + port: common.port, + path: '/' + }, function(err, res) { + + if (err) { + throw err; + } + + assert.strictEqual(res.statusCode, 200); + server.close(); + }); + +}); + +process.on('exit', function() { + assert.strictEqual(FIELDS.length, 0); +}); diff --git a/node_modules/request/node_modules/form-data/test/integration/test-submit.js b/node_modules/request/node_modules/form-data/test/integration/test-submit.js new file mode 100644 index 000000000..b6e2c07a3 --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/integration/test-submit.js @@ -0,0 +1,117 @@ +var common = require('../common'); +var assert = common.assert; +var http = require('http'); +var path = require('path'); +var mime = require('mime'); +var request = require('request'); +var fs = require('fs'); +var FormData = require(common.dir.lib + '/form_data'); +var IncomingForm = require('formidable').IncomingForm; + +var remoteFile = 'http://nodejs.org/images/logo.png'; + +// wrap non simple values into function +// just to deal with ReadStream "autostart" +// Can't wait for 0.10 +var FIELDS = [ + {name: 'my_field', value: 'my_value'}, + {name: 'my_buffer', value: function(){ return new Buffer([1, 2, 3])} }, + {name: 'my_file', value: function(){ return fs.createReadStream(common.dir.fixture + '/unicycle.jpg')} }, + {name: 'remote_file', value: function(){ return request(remoteFile)} } +]; + +var server = http.createServer(function(req, res) { + + // formidable is fixed on github + // but still 7 month old in npm + // + // var form = new IncomingForm(); + // form.uploadDir = common.dir.tmp; + // form.parse(req); + // form + // .on('field', function(name, value) { + // var field = FIELDS.shift(); + // assert.strictEqual(name, field.name); + // assert.strictEqual(value, field.value+''); + // }) + // .on('file', function(name, file) { + // var field = FIELDS.shift(); + // assert.strictEqual(name, field.name); + // assert.strictEqual(file.name, path.basename(field.value.path)); + // // mime.lookup file.NAME == 'my_file' ? + // assert.strictEqual(file.type, mime.lookup(file.name)); + // }) + // .on('end', function() { + // res.writeHead(200); + // res.end('done'); + // }); + + // temp workaround + var data = ''; + req.setEncoding('utf8'); + req.on('data', function(d) { + data += d; + }); + req.on('end', function() { + // check for the fields' traces + + // 1st field : my_field + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 2nd field : my_buffer + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 3rd field : my_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 ); + // check for unicycle.jpg traces + assert.ok( data.indexOf('2005:06:21 01:44:12') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(field.value.path) ) != -1 ); + + // 4th field : remote_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 ); + // check for http://nodejs.org/images/logo.png traces + assert.ok( data.indexOf('ImageReady') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(remoteFile) ) != -1 ); + + res.writeHead(200); + res.end('done'); + + }); + +}); + +server.listen(common.port, function() { + + var form = new FormData(); + + FIELDS.forEach(function(field) { + // important to append ReadStreams within the same tick + if ((typeof field.value == 'function')) { + field.value = field.value(); + } + form.append(field.name, field.value); + }); + + form.submit('http://localhost:' + common.port + '/', function(err, res) { + + if (err) { + throw err; + } + + assert.strictEqual(res.statusCode, 200); + server.close(); + }); + +}); + +process.on('exit', function() { + assert.strictEqual(FIELDS.length, 0); +}); diff --git a/node_modules/request/node_modules/form-data/test/run.js b/node_modules/request/node_modules/form-data/test/run.js new file mode 100755 index 000000000..0bb8e8224 --- /dev/null +++ b/node_modules/request/node_modules/form-data/test/run.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var far = require('far').create(); + +far.add(__dirname); +far.include(/test-.*\.js$/); + +far.execute(); diff --git a/node_modules/request/node_modules/hawk/.npmignore b/node_modules/request/node_modules/hawk/.npmignore new file mode 100644 index 000000000..77ba16cb0 --- /dev/null +++ b/node_modules/request/node_modules/hawk/.npmignore @@ -0,0 +1,18 @@ +.idea +*.iml +npm-debug.log +dump.rdb +node_modules +results.tap +results.xml +npm-shrinkwrap.json +config.json +.DS_Store +*/.DS_Store +*/*/.DS_Store +._* +*/._* +*/*/._* +coverage.* +lib-cov + diff --git a/node_modules/request/node_modules/hawk/.travis.yml b/node_modules/request/node_modules/hawk/.travis.yml new file mode 100755 index 000000000..d8523c933 --- /dev/null +++ b/node_modules/request/node_modules/hawk/.travis.yml @@ -0,0 +1,5 @@ +language: node_js + +node_js: + - 0.8 + diff --git a/node_modules/request/node_modules/hawk/LICENSE b/node_modules/request/node_modules/hawk/LICENSE new file mode 100755 index 000000000..e699a7bdb --- /dev/null +++ b/node_modules/request/node_modules/hawk/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2012-2013, Eran Hammer. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Eran Hammer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ERAN HAMMER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/request/node_modules/hawk/Makefile b/node_modules/request/node_modules/hawk/Makefile new file mode 100755 index 000000000..97ba3af43 --- /dev/null +++ b/node_modules/request/node_modules/hawk/Makefile @@ -0,0 +1,11 @@ +test:
+ @./node_modules/.bin/lab
+test-cov:
+ @./node_modules/.bin/lab -r threshold -t 100
+test-cov-html:
+ @./node_modules/.bin/lab -r html -o coverage.html
+complexity:
+ @./node_modules/.bin/cr -o complexity.md -f markdown lib
+
+.PHONY: test test-cov test-cov-html complexity
+
diff --git a/node_modules/request/node_modules/hawk/README.md b/node_modules/request/node_modules/hawk/README.md new file mode 100755 index 000000000..66b52cbbd --- /dev/null +++ b/node_modules/request/node_modules/hawk/README.md @@ -0,0 +1,604 @@ +![hawk Logo](https://raw.github.com/hueniverse/hawk/master/images/hawk.png)
+
+<img align="right" src="https://raw.github.com/hueniverse/hawk/master/images/logo.png" /> **Hawk** is an HTTP authentication scheme using a message authentication code (MAC) algorithm to provide partial
+HTTP request cryptographic verification. For more complex use cases such as access delegation, see [Oz](https://github.com/hueniverse/oz).
+
+Current version: **0.10.1**
+
+[![Build Status](https://secure.travis-ci.org/hueniverse/hawk.png)](http://travis-ci.org/hueniverse/hawk)
+
+# Table of Content
+
+- [**Introduction**](#introduction)
+ - [Replay Protection](#replay-protection)
+ - [Usage Example](#usage-example)
+ - [Protocol Example](#protocol-example)
+ - [Payload Validation](#payload-validation)
+ - [Response Payload Validation](#response-payload-validation)
+<p></p>
+- [**Single URI Authorization**](#single-uri-authorization)
+ - [Usage Example](#bewit-usage-example)
+<p></p>
+- [**Security Considerations**](#security-considerations)
+ - [MAC Keys Transmission](#mac-keys-transmission)
+ - [Confidentiality of Requests](#confidentiality-of-requests)
+ - [Spoofing by Counterfeit Servers](#spoofing-by-counterfeit-servers)
+ - [Plaintext Storage of Credentials](#plaintext-storage-of-credentials)
+ - [Entropy of Keys](#entropy-of-keys)
+ - [Coverage Limitations](#coverage-limitations)
+ - [Future Time Manipulation](#future-time-manipulation)
+ - [Client Clock Poisoning](#client-clock-poisoning)
+ - [Bewit Limitations](#bewit-limitations)
+<p></p>
+- [**Frequently Asked Questions**](#frequently-asked-questions)
+<p></p>
+- [**Acknowledgements**](#acknowledgements)
+
+# Introduction
+
+**Hawk** is an HTTP authentication scheme providing mechanisms for making authenticated HTTP requests with
+partial cryptographic verification of the request and response, covering the HTTP method, request URI, host,
+and optionally the request payload.
+
+Similar to the HTTP [Digest access authentication schemes](http://www.ietf.org/rfc/rfc2617.txt), **Hawk** uses a set of
+client credentials which include an identifier (e.g. username) and key (e.g. password). Likewise, just as with the Digest scheme,
+the key is never included in authenticated requests. Instead, it is used to calculate a request MAC value which is
+included in its place.
+
+However, **Hawk** has several differences from Digest. In particular, while both use a nonce to limit the possibility of
+replay attacks, in **Hawk** the client generates the nonce and uses it in combination with a timestamp, leading to less
+"chattiness" (interaction with the server).
+
+Also unlike Digest, this scheme is not intended to protect the key itself (the password in Digest) because
+the client and server must both have access to the key material in the clear.
+
+The primary design goals of this scheme are to:
+* simplify and improve HTTP authentication for services that are unwilling or unable to deploy TLS for all resources,
+* secure credentials against leakage (e.g., when the client uses some form of dynamic configuration to determine where
+ to send an authenticated request), and
+* avoid the exposure of credentials sent to a malicious server over an unauthenticated secure channel due to client
+ failure to validate the server's identity as part of its TLS handshake.
+
+In addition, **Hawk** supports a method for granting third-parties temporary access to individual resources using
+a query parameter called _bewit_ (in falconry, a leather strap used to attach a tracking device to the leg of a hawk).
+
+The **Hawk** scheme requires the establishment of a shared symmetric key between the client and the server,
+which is beyond the scope of this module. Typically, the shared credentials are established via an initial
+TLS-protected phase or derived from some other shared confidential information available to both the client
+and the server.
+
+
+## Replay Protection
+
+Without replay protection, an attacker can use a compromised (but otherwise valid and authenticated) request more
+than once, gaining access to a protected resource. To mitigate this, clients include both a nonce and a timestamp when
+making requests. This gives the server enough information to prevent replay attacks.
+
+The nonce is generated by the client, and is a string unique across all requests with the same timestamp and
+key identifier combination.
+
+The timestamp enables the server to restrict the validity period of the credentials where requests occuring afterwards
+are rejected. It also removes the need for the server to retain an unbounded number of nonce values for future checks.
+By default, **Hawk** uses a time window of 1 minute to allow for time skew between the client and server (which in
+practice translates to a maximum of 2 minutes as the skew can be positive or negative).
+
+Using a timestamp requires the client's clock to be in sync with the server's clock. **Hawk** requires both the client
+clock and the server clock to use NTP to ensure synchronization. However, given the limitations of some client types
+(e.g. browsers) to deploy NTP, the server provides the client with its current time in response to a bad timestamp.
+
+There is no expectation that the client will adjust its system clock to match the server (in fact, this would be a
+potential attack vector). Instead, the client only uses the server's time to calculate an offset used only
+for communications with that particular server. The protocol rewards clients with synchronized clocks by reducing
+the number of round trips required to authenticate the first request.
+
+
+## Usage Example
+
+Server code:
+
+```javascript
+var Http = require('http');
+var Hawk = require('hawk');
+
+
+// Credentials lookup function
+
+var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256',
+ user: 'Steve'
+ };
+
+ return callback(null, credentials);
+};
+
+// Create HTTP server
+
+var handler = function (req, res) {
+
+ // Authenticate incoming request
+
+ Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+
+ // Prepare response
+
+ var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');
+ var headers = { 'Content-Type': 'text/plain' };
+
+ // Generate Server-Authorization response header
+
+ var header = Hawk.server.header(artifacts, { payload: payload, contentType: headers['Content-Type'] });
+ headers['Server-Authorization'] = header;
+
+ // Send the response back
+
+ res.writeHead(!err ? 200 : 401, headers);
+ res.end(payload);
+ });
+};
+
+// Start server
+
+Http.createServer(handler).listen(8000, 'example.com');
+```
+
+Client code:
+
+```javascript
+var Request = require('request');
+var Hawk = require('hawk');
+
+
+// Client credentials
+
+var credentials = {
+ id: 'dh37fgj492je',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256'
+}
+
+// Request options
+
+var requestOptions = {
+ uri: 'http://example.com:8000/resource/1?b=1&a=2',
+ method: 'GET',
+ headers: {}
+};
+
+// Generate Authorization request header
+
+var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' });
+requestOptions.headers.Authorization = header.field;
+
+// Send authenticated request
+
+Request(requestOptions, function (error, response, body) {
+
+ // Authenticate the server's response
+
+ var isValid = Hawk.client.authenticate(response, header.artifacts, { payload: body });
+
+ // Output results
+
+ console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));
+});
+```
+
+**Hawk** utilized the [**SNTP**](https://github.com/hueniverse/sntp) module for time sync management. By default, the local
+machine time is used. To automatically retrieve and synchronice the clock within the application, use the SNTP 'start()' method.
+
+```javascript
+Hawk.sntp.start();
+```
+
+
+## Protocol Example
+
+The client attempts to access a protected resource without authentication, sending the following HTTP request to
+the resource server:
+
+```
+GET /resource/1?b=1&a=2 HTTP/1.1
+Host: example.com:8000
+```
+
+The resource server returns an authentication challenge.
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Hawk
+```
+
+The client has previously obtained a set of **Hawk** credentials for accessing resources on the "http://example.com/"
+server. The **Hawk** credentials issued to the client include the following attributes:
+
+* Key identifier: dh37fgj492je
+* Key: werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn
+* Algorithm: sha256
+
+The client generates the authentication header by calculating a timestamp (e.g. the number of seconds since January 1,
+1970 00:00:00 GMT), generating a nonce, and constructing the normalized request string (each value followed by a newline
+character):
+
+```
+hawk.1.header
+1353832234
+j4h3g2
+GET
+/resource?a=1&b=2
+example.com
+8000
+
+some-app-ext-data
+
+```
+
+The request MAC is calculated using HMAC with the specified hash algorithm "sha256" and the key over the normalized request string.
+The result is base64-encoded to produce the request MAC:
+
+```
+6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=
+```
+
+The client includes the **Hawk** key identifier, timestamp, nonce, application specific data, and request MAC with the request using
+the HTTP `Authorization` request header field:
+
+```
+GET /resource/1?b=1&a=2 HTTP/1.1
+Host: example.com:8000
+Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="
+```
+
+The server validates the request by calculating the request MAC again based on the request received and verifies the validity
+and scope of the **Hawk** credentials. If valid, the server responds with the requested resource.
+
+
+### Payload Validation
+
+**Hawk** provides optional payload validation. When generating the authentication header, the client calculates a payload hash
+using the specified hash algorithm. The hash is calculated over the concatenated value of (each followed by a newline character):
+* `hawk.1.payload`
+* the content-type in lowercase, without any parameters (e.g. `application/json`)
+* the request payload prior to any content encoding (the exact representation requirements should be specified by the server for payloads other than simple single-part ascii to ensure interoperability)
+
+For example:
+
+* Payload: `Thank you for flying Hawk`
+* Content Type: `text/plain`
+* Hash (sha256): `Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=`
+
+Results in the following input to the payload hash function (newline terminated values):
+
+```
+hawk.1.payload
+text/plain
+Thank you for flying Hawk
+
+```
+
+Which produces the following hash value:
+
+```
+Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=
+```
+
+The client constructs the normalized request string (newline terminated values):
+
+```
+hawk.1.header
+1353832234
+j4h3g2
+POST
+/resource?a=1&b=2
+example.com
+8000
+Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=
+some-app-ext-data
+
+```
+
+Then calculates the request MAC and includes the **Hawk** key identifier, timestamp, nonce, payload hash, application specific data,
+and request MAC, with the request using the HTTP `Authorization` request header field:
+
+```
+POST /resource/1 HTTP/1.1
+Host: example.com:8000
+Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="
+```
+
+It is up to the server if and when it validates the payload for any given request, based solely on it's security policy
+and the nature of the data included.
+
+If the payload is available at the time of authentication, the server uses the hash value provided by the client to construct
+the normalized string and validates the MAC. If the MAC is valid, the server calculates the payload hash and compares the value
+with the provided payload hash in the header. In many cases, checking the MAC first is faster than calculating the payload hash.
+
+However, if the payload is not available at authentication time (e.g. too large to fit in memory, streamed elsewhere, or processed
+at a different stage in the application), the server may choose to defer payload validation for later by retaining the hash value
+provided by the client after validating the MAC.
+
+It is important to note that MAC validation does not mean the hash value provided by the client is valid, only that the value
+included in the header was not modified. Without calculating the payload hash on the server and comparing it to the value provided
+by the client, the payload may be modified by an attacker.
+
+
+## Response Payload Validation
+
+**Hawk** provides partial response payload validation. The server includes the `Server-Authorization` response header which enables the
+client to authenticate the response and ensure it is talking to the right server. **Hawk** defines the HTTP `Server-Authorization` header
+as a response header using the exact same syntax as the `Authorization` request header field.
+
+The header is contructed using the same process as the client's request header. The server uses the same credentials and other
+artifacts provided by the client to constructs the normalized request string. The `ext` and `hash` values are replaced with
+new values based on the server response. The rest as identical to those used by the client.
+
+The result MAC digest is included with the optional `hash` and `ext` values:
+
+```
+Server-Authorization: Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"
+```
+
+
+# Single URI Authorization
+
+There are cases in which limited and short-term access to a protected resource is granted to a third party which does not
+have access to the shared credentials. For example, displaying a protected image on a web page accessed by anyone. **Hawk**
+provides limited support for such URIs in the form of a _bewit_ - a URI query parameter appended to the request URI which contains
+the necessary credentials to authenticate the request.
+
+Because of the significant security risks involved in issuing such access, bewit usage is purposely limited only to GET requests
+and for a finite period of time. Both the client and server can issue bewit credentials, however, the server should not use the same
+credentials as the client to maintain clear traceability as to who issued which credentials.
+
+In order to simplify implementation, bewit credentials do not support single-use policy and can be replayed multiple times within
+the granted access timeframe.
+
+
+## Bewit Usage Example
+
+Server code:
+
+```javascript
+var Http = require('http');
+var Hawk = require('hawk');
+
+
+// Credentials lookup function
+
+var credentialsFunc = function (id, callback) {
+
+ var credentials = {
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256'
+ };
+
+ return callback(null, credentials);
+};
+
+// Create HTTP server
+
+var handler = function (req, res) {
+
+ Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+
+ res.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' });
+ res.end(!err ? 'Access granted' : 'Shoosh!');
+ });
+};
+
+Http.createServer(handler).listen(8000, 'example.com');
+```
+
+Bewit code generation:
+
+```javascript
+var Request = require('request');
+var Hawk = require('hawk');
+
+
+// Client credentials
+
+var credentials = {
+ id: 'dh37fgj492je',
+ key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
+ algorithm: 'sha256'
+}
+
+// Generate bewit
+
+var duration = 60 * 5; // 5 Minutes
+var bewit = Hawk.uri.getBewit('http://example.com:8080/resource/1?b=1&a=2', { credentials: credentials, ttlSec: duration, ext: 'some-app-data' });
+var uri = 'http://example.com:8000/resource/1?b=1&a=2' + '&bewit=' + bewit;
+```
+
+
+# Security Considerations
+
+The greatest sources of security risks are usually found not in **Hawk** but in the policies and procedures surrounding its use.
+Implementers are strongly encouraged to assess how this module addresses their security requirements. This section includes
+an incomplete list of security considerations that must be reviewed and understood before deploying **Hawk** on the server.
+Many of the protections provided in **Hawk** depends on whether and how they are used.
+
+### MAC Keys Transmission
+
+**Hawk** does not provide any mechanism for obtaining or transmitting the set of shared credentials required. Any mechanism used
+to obtain **Hawk** credentials must ensure that these transmissions are protected using transport-layer mechanisms such as TLS.
+
+### Confidentiality of Requests
+
+While **Hawk** provides a mechanism for verifying the integrity of HTTP requests, it provides no guarantee of request
+confidentiality. Unless other precautions are taken, eavesdroppers will have full access to the request content. Servers should
+carefully consider the types of data likely to be sent as part of such requests, and employ transport-layer security mechanisms
+to protect sensitive resources.
+
+### Spoofing by Counterfeit Servers
+
+**Hawk** provides limited verification of the server authenticity. When receiving a response back from the server, the server
+may choose to include a response `Server-Authorization` header which the client can use to verify the response. However, it is up to
+the server to determine when such measure is included, to up to the client to enforce that policy.
+
+A hostile party could take advantage of this by intercepting the client's requests and returning misleading or otherwise
+incorrect responses. Service providers should consider such attacks when developing services using this protocol, and should
+require transport-layer security for any requests where the authenticity of the resource server or of server responses is an issue.
+
+### Plaintext Storage of Credentials
+
+The **Hawk** key functions the same way passwords do in traditional authentication systems. In order to compute the request MAC,
+the server must have access to the key in plaintext form. This is in contrast, for example, to modern operating systems, which
+store only a one-way hash of user credentials.
+
+If an attacker were to gain access to these keys - or worse, to the server's database of all such keys - he or she would be able
+to perform any action on behalf of any resource owner. Accordingly, it is critical that servers protect these keys from unauthorized
+access.
+
+### Entropy of Keys
+
+Unless a transport-layer security protocol is used, eavesdroppers will have full access to authenticated requests and request
+MAC values, and will thus be able to mount offline brute-force attacks to recover the key used. Servers should be careful to
+assign keys which are long enough, and random enough, to resist such attacks for at least the length of time that the **Hawk**
+credentials are valid.
+
+For example, if the credentials are valid for two weeks, servers should ensure that it is not possible to mount a brute force
+attack that recovers the key in less than two weeks. Of course, servers are urged to err on the side of caution, and use the
+longest key reasonable.
+
+It is equally important that the pseudo-random number generator (PRNG) used to generate these keys be of sufficiently high
+quality. Many PRNG implementations generate number sequences that may appear to be random, but which nevertheless exhibit
+patterns or other weaknesses which make cryptanalysis or brute force attacks easier. Implementers should be careful to use
+cryptographically secure PRNGs to avoid these problems.
+
+### Coverage Limitations
+
+The request MAC only covers the HTTP `Host` header and optionally the `Content-Type` header. It does not cover any other headers
+which can often affect how the request body is interpreted by the server. If the server behavior is influenced by the presence
+or value of such headers, an attacker can manipulate the request headers without being detected. Implementers should use the
+`ext` feature to pass application-specific information via the `Authorization` header which is protected by the request MAC.
+
+The response authentication, when performed, only covers the response payload, content-type, and the request information
+provided by the client in it's request (method, resource, timestamp, nonce, etc.). It does not cover the HTTP status code or
+any other response header field (e.g. Location) which can affect the client's behaviour.
+
+### Future Time Manipulation
+
+The protocol relies on a clock sync between the client and server. To accomplish this, the server informs the client of its
+current time when an invalid timestamp is received.
+
+If an attacker is able to manipulate this information and cause the client to use an incorrect time, it would be able to cause
+the client to generate authenticated requests using time in the future. Such requests will fail when sent by the client, and will
+not likely leave a trace on the server (given the common implementation of nonce, if at all enforced). The attacker will then
+be able to replay the request at the correct time without detection.
+
+The client must only use the time information provided by the server if:
+* it was delivered over a TLS connection and the server identity has been verified, or
+* the `tsm` MAC digest calculated using the same client credentials over the timestamp has been verified.
+
+### Client Clock Poisoning
+
+When receiving a request with a bad timestamp, the server provides the client with its current time. The client must never use
+the time received from the server to adjust its own clock, and must only use it to calculate an offset for communicating with
+that particular server.
+
+### Bewit Limitations
+
+Special care must be taken when issuing bewit credentials to third parties. Bewit credentials are valid until expiration and cannot
+be revoked or limited without using other means. Whatever resource they grant access to will be completely exposed to anyone with
+access to the bewit credentials which act as bearer credentials for that particular resource. While bewit usage is limited to GET
+requests only and therefore cannot be used to perform transactions or change server state, it can still be used to expose private
+and sensitive information.
+
+
+# Frequently Asked Questions
+
+### Where is the protocol specification?
+
+If you are looking for some prose explaining how all this works, **this is it**. **Hawk** is being developed as an open source
+project instead of a standard. In other words, the [code](/hueniverse/hawk/tree/master/lib) is the specification. Not sure about
+something? Open an issue!
+
+### Is it done?
+
+At if version 0.10.0, **Hawk** is feature-complete. However, until this module reaches version 1.0.0 it is considered experimental
+and is likely to change. This also means your feedback and contribution are very welcome. Feel free to open issues with questions
+and suggestions.
+
+### Where can I find **Hawk** implementations in other languages?
+
+**Hawk**'s only reference implementation is provided in JavaScript as a node.js module. However, others are actively porting it to other
+platforms. There is already a [PHP](https://github.com/alexbilbie/PHP-Hawk),
+[.NET](https://github.com/pcibraro/hawknet), and [JAVA](https://github.com/wealdtech/hawk) libraries available. The full list
+is maintained [here](https://github.com/hueniverse/hawk/issues?labels=port). Please add an issue if you are working on another
+port. A cross-platform test-suite is in the works.
+
+### Why isn't the algorithm part of the challenge or dynamically negotiated?
+
+The algorithm used is closely related to the key issued as different algorithms require different key sizes (and other
+requirements). While some keys can be used for multiple algorithm, the protocol is designed to closely bind the key and algorithm
+together as part of the issued credentials.
+
+### Why is Host and Content-Type the only headers covered by the request MAC?
+
+It is really hard to include other headers. Headers can be changed by proxies and other intermediaries and there is no
+well-established way to normalize them. Many platforms change the case of header field names and values. The only
+straight-forward solution is to include the headers in some blob (say, base64 encoded JSON) and include that with the request,
+an approach taken by JWT and other such formats. However, that design violates the HTTP header boundaries, repeats information,
+and introduces other security issues because firewalls will not be aware of these "hidden" headers. In addition, any information
+repeated must be compared to the duplicated information in the header and therefore only moves the problem elsewhere.
+
+### Why not just use HTTP Digest?
+
+Digest requires pre-negotiation to establish a nonce. This means you can't just make a request - you must first send
+a protocol handshake to the server. This pattern has become unacceptable for most web services, especially mobile
+where extra round-trip are costly.
+
+### Why bother with all this nonce and timestamp business?
+
+**Hawk** is an attempt to find a reasonable, practical compromise between security and usability. OAuth 1.0 got timestamp
+and nonces halfway right but failed when it came to scalability and consistent developer experience. **Hawk** addresses
+it by requiring the client to sync its clock, but provides it with tools to accomplish it.
+
+In general, replay protection is a matter of application-specific threat model. It is less of an issue on a TLS-protected
+system where the clients are implemented using best practices and are under the control of the server. Instead of dropping
+replay protection, **Hawk** offers a required time window and an optional nonce verification. Together, it provides developers
+with the ability to decide how to enforce their security policy without impacting the client's implementation.
+
+### What are `app` and `dlg` in the authorization header and normalized mac string?
+
+The original motivation for **Hawk** was to replace the OAuth 1.0 use cases. This included both a simple client-server mode which
+this module is specifically designed for, and a delegated access mode which is being developed separately in
+[Oz](https://github.com/hueniverse/oz). In addition to the **Hawk** use cases, Oz requires another attribute: the application id `app`.
+This provides binding between the credentials and the application in a way that prevents an attacker from tricking an application
+to use credentials issued to someone else. It also has an optional 'delegated-by' attribute `dlg` which is the application id of the
+application the credentials were directly issued to. The goal of these two additions is to allow Oz to utilize **Hawk** directly,
+but with the additional security of delegated credentials.
+
+### What is the purpose of the static strings used in each normalized MAC input?
+
+When calculating a hash or MAC, a static prefix (tag) is added. The prefix is used to prevent MAC values from being
+used or reused for a purpose other than what they were created for (i.e. prevents switching MAC values between a request,
+response, and a bewit use cases). It also protects against expliots created after a potential change in how the protocol
+creates the normalized string. For example, if a future version would switch the order of nonce and timestamp, it
+can create an exploit opportunity for cases where the nonce is similar in format to a timestamp.
+
+### Does **Hawk** have anything to do with OAuth?
+
+Short answer: no.
+
+**Hawk** was originally proposed as the OAuth MAC Token specification. However, the OAuth working group in its consistent
+incompetence failed to produce a final, usable solution to address one of the most popular use cases of OAuth 1.0 - using it
+to authenticate simple client-server transactions (i.e. two-legged). As you can guess, the OAuth working group is still hard
+at work to produce more garbage.
+
+**Hawk** provides a simple HTTP authentication scheme for making client-server requests. It does not address the OAuth use case
+of delegating access to a third party. If you are looking for an OAuth alternative, check out [Oz](/hueniverse/oz).
+
+
+# Acknowledgements
+
+**Hawk** is a derivative work of the [HTTP MAC Authentication Scheme](http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05) proposal
+co-authored by Ben Adida, Adam Barth, and Eran Hammer, which in turn was based on the OAuth 1.0 community specification.
+
+Special thanks to Ben Laurie for his always insightful feedback and advice.
+
+The **Hawk** logo was created by [Chris Carrasco](http://chriscarrasco.com).
diff --git a/node_modules/request/node_modules/hawk/example/usage.js b/node_modules/request/node_modules/hawk/example/usage.js new file mode 100755 index 000000000..1f78f9a56 --- /dev/null +++ b/node_modules/request/node_modules/hawk/example/usage.js @@ -0,0 +1,77 @@ +// Load modules + +var Http = require('http'); +var Request = require('request'); +var Hawk = require('../lib'); + + +// Declare internals + +var internals = {
+ credentials: {
+ dh37fgj492je: {
+ id: 'dh37fgj492je', // Required by Hawk.client.header + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: 'sha256', + user: 'Steve'
+ }
+ }
+}; + + +// Credentials lookup function + +var credentialsFunc = function (id, callback) {
+ + return callback(null, internals.credentials[id]);
+}; + + +// Create HTTP server + +var handler = function (req, res) {
+ + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+ + var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!'); + var headers = {
+ 'Content-Type': 'text/plain',
+ 'Server-Authorization': Hawk.server.header(artifacts, { payload: payload, contentType: 'text/plain' })
+ }; + + res.writeHead(!err ? 200 : 401, headers); + res.end(payload);
+ });
+}; + +Http.createServer(handler).listen(8000, '127.0.0.1'); + + +// Send unauthenticated request + +Request('http://127.0.0.1:8000/resource/1?b=1&a=2', function (error, response, body) {
+ + console.log(response.statusCode + ': ' + body);
+}); + + +// Send authenticated request + +var header = Hawk.client.header('http://127.0.0.1:8000/resource/1?b=1&a=2', 'GET', { credentials: internals.credentials.dh37fgj492je, ext: 'and welcome!' }); +var options = {
+ uri: 'http://127.0.0.1:8000/resource/1?b=1&a=2', + method: 'GET', + headers: {
+ authorization: header.field
+ }
+}; + + +Request(options, function (error, response, body) {
+ + var isValid = Hawk.client.authenticate(response, header.artifacts, { payload: body }); + console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)')); + process.exit(0);
+}); + + diff --git a/node_modules/request/node_modules/hawk/images/hawk.png b/node_modules/request/node_modules/hawk/images/hawk.png Binary files differnew file mode 100755 index 000000000..a0e15cda0 --- /dev/null +++ b/node_modules/request/node_modules/hawk/images/hawk.png diff --git a/node_modules/request/node_modules/hawk/images/logo.png b/node_modules/request/node_modules/hawk/images/logo.png Binary files differnew file mode 100755 index 000000000..b8ff59017 --- /dev/null +++ b/node_modules/request/node_modules/hawk/images/logo.png diff --git a/node_modules/request/node_modules/hawk/index.js b/node_modules/request/node_modules/hawk/index.js new file mode 100755 index 000000000..4cc88b358 --- /dev/null +++ b/node_modules/request/node_modules/hawk/index.js @@ -0,0 +1 @@ +module.exports = require('./lib');
\ No newline at end of file diff --git a/node_modules/request/node_modules/hawk/lib/client.js b/node_modules/request/node_modules/hawk/lib/client.js new file mode 100755 index 000000000..256363d4d --- /dev/null +++ b/node_modules/request/node_modules/hawk/lib/client.js @@ -0,0 +1,200 @@ +// Load modules + +var Url = require('url'); +var Hoek = require('hoek'); +var Cryptiles = require('cryptiles'); +var Crypto = require('./crypto'); +var Utils = require('./utils'); + + +// Declare internals + +var internals = {}; + + +// Generate an Authorization header for a given request + +/* + uri: 'http://example.com/resource?a=b' or object from Url.parse() + method: HTTP verb (e.g. 'GET', 'POST') + options: { + + // Required + + credentials: { + id: 'dh37fgj492je', + key: 'aoijedoaijsdlaksjdl', + algorithm: 'sha256' // 'sha1', 'sha256' + }, + + // Optional + + ext: 'application-specific', // Application specific data sent via the ext attribute + timestamp: Date.now(), // A pre-calculated timestamp + nonce: '2334f34f', // A pre-generated nonce + localtimeOffsetMsec: 400, // Time offset to sync with server time (ignored if timestamp provided) + payload: '{"some":"payload"}', // UTF-8 encoded string for body hash generation (ignored if hash provided) + contentType: 'application/json', // Payload content-type (ignored if hash provided) + hash: 'U4MKKSmiVxk37JCCrAVIjV=', // Pre-calculated payload hash + app: '24s23423f34dx', // Oz application id + dlg: '234sz34tww3sd' // Oz delegated-by application id + } +*/ + +exports.header = function (uri, method, options) { + + var result = { + field: '', + artifacts: {} + }; + + // Validate inputs + + if (!uri || (typeof uri !== 'string' && typeof uri !== 'object') || + !method || typeof method !== 'string' || + !options || typeof options !== 'object') { + + return result; + } + + // Application time + + var timestamp = options.timestamp || Math.floor((Utils.now() + (options.localtimeOffsetMsec || 0)) / 1000) + + // Validate credentials + + var credentials = options.credentials; + if (!credentials || + !credentials.id || + !credentials.key || + !credentials.algorithm) { + + // Invalid credential object + return result; + } + + if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) { + return result; + } + + // Parse URI + + if (typeof uri === 'string') { + uri = Url.parse(uri); + } + + // Calculate signature + + var artifacts = { + credentials: credentials, + ts: timestamp, + nonce: options.nonce || Cryptiles.randomString(6), + method: method, + resource: uri.pathname + (uri.search || ''), // Maintain trailing '?' + host: uri.hostname, + port: uri.port || (uri.protocol === 'http:' ? 80 : 443), + hash: options.hash, + ext: options.ext, + app: options.app, + dlg: options.dlg + }; + + result.artifacts = artifacts; + + // Calculate payload hash + + if (!artifacts.hash && + options.hasOwnProperty('payload')) { + + artifacts.hash = Crypto.calculateHash(options.payload, credentials.algorithm, options.contentType); + } + + var mac = Crypto.calculateMac('header', artifacts); + + // Construct header + + var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== ''; // Other falsey values allowed + var header = 'Hawk id="' + credentials.id + + '", ts="' + artifacts.ts + + '", nonce="' + artifacts.nonce + + (artifacts.hash ? '", hash="' + artifacts.hash : '') + + (hasExt ? '", ext="' + Utils.escapeHeaderAttribute(artifacts.ext) : '') + + '", mac="' + mac + '"'; + + if (artifacts.app) { + header += ', app="' + artifacts.app + + (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"'; + } + + result.field = header; + + return result; +}; + + +// Validate server response + +/* + res: node's response object + artifacts: object recieved from header().artifacts + options: { + payload: optional payload received + required: specifies if a Server-Authorization header is required. Defaults to 'false' + } +*/ + +exports.authenticate = function (res, artifacts, options) { + + artifacts = Hoek.clone(artifacts); + options = options || {}; + + if (res.headers['www-authenticate']) { + + // Parse HTTP WWW-Authenticate header + + var attributes = Utils.parseAuthorizationHeader(res.headers['www-authenticate'], ['ts', 'tsm', 'error']); + if (attributes instanceof Error) { + return false; + } + + if (attributes.ts) { + var tsm = Crypto.calculateTsMac(attributes.ts, artifacts.credentials); + if (!Cryptiles.fixedTimeComparison(tsm, attributes.tsm)) { + return false; + } + } + } + + // Parse HTTP Server-Authorization header + + if (!res.headers['server-authorization'] && + !options.required) { + + return true; + } + + var attributes = Utils.parseAuthorizationHeader(res.headers['server-authorization'], ['mac', 'ext', 'hash']); + if (attributes instanceof Error) { + return false; + } + + artifacts.ext = attributes.ext; + artifacts.hash = attributes.hash; + + var mac = Crypto.calculateMac('response', artifacts); + if (!Cryptiles.fixedTimeComparison(mac, attributes.mac)) { + return false; + } + + if (!options.hasOwnProperty('payload')) { + return true; + } + + if (!attributes.hash) {
+ return false;
+ } + + var calculatedHash = Crypto.calculateHash(options.payload, artifacts.credentials.algorithm, res.headers['content-type']); + return Cryptiles.fixedTimeComparison(calculatedHash, attributes.hash); +}; + diff --git a/node_modules/request/node_modules/hawk/lib/crypto.js b/node_modules/request/node_modules/hawk/lib/crypto.js new file mode 100755 index 000000000..7e8135338 --- /dev/null +++ b/node_modules/request/node_modules/hawk/lib/crypto.js @@ -0,0 +1,98 @@ +// Load modules + +var Crypto = require('crypto'); +var Url = require('url'); +var Utils = require('./utils'); + + +// Declare internals + +var internals = {}; + + +// MAC normalization format version + +exports.headerVersion = '1'; // Prevent comparison of mac values generated with different normalized string formats + + +// Supported HMAC algorithms + +exports.algorithms = ['sha1', 'sha256']; + + +// Calculate the request MAC + +/* + type: 'header' // 'header', 'bewit', 'response' + options: { + credentials: { + key: 'aoijedoaijsdlaksjdl', + algorithm: 'sha256' // 'sha1', 'sha256' + }, + method: 'GET', + resource: '/resource?a=1&b=2', + host: 'example.com', + port: 8080, + ts: 1357718381034, + nonce: 'd3d345f', + hash: 'U4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=', + ext: 'app-specific-data', + app: 'hf48hd83qwkj', // Application id (Oz) + dlg: 'd8djwekds9cj' // Delegated by application id (Oz), requires options.app + } +*/ + +exports.calculateMac = function (type, options) { + + var normalized = exports.generateNormalizedString(type, options); + + var hmac = Crypto.createHmac(options.credentials.algorithm, options.credentials.key).update(normalized); + var digest = hmac.digest('base64'); + return digest; +}; + + +exports.generateNormalizedString = function (type, options) { + + var normalized = 'hawk.' + exports.headerVersion + '.' + type + '\n' + + options.ts + '\n' + + options.nonce + '\n' + + options.method.toUpperCase() + '\n' + + options.resource + '\n' + + options.host.toLowerCase() + '\n' + + options.port + '\n' + + (options.hash || '') + '\n'; + + if (options.ext) {
+ normalized += options.ext.replace('\\', '\\\\').replace('\n', '\\n');
+ } + + normalized += '\n'; + + if (options.app) {
+ normalized += options.app + '\n' +
+ (options.dlg || '') + '\n';
+ } + + return normalized; +}; + + +exports.calculateHash = function (payload, algorithm, contentType) { + + var hash = Crypto.createHash(algorithm); + hash.update('hawk.' + exports.headerVersion + '.payload\n'); + hash.update(Utils.parseContentType(contentType) + '\n'); + hash.update(payload || ''); + hash.update('\n'); + return hash.digest('base64'); +}; + + +exports.calculateTsMac = function (ts, credentials) {
+ + var hash = Crypto.createHash(credentials.algorithm); + hash.update('hawk.' + exports.headerVersion + '.ts\n' + ts + '\n'); + return hash.digest('base64');
+}; + diff --git a/node_modules/request/node_modules/hawk/lib/index.js b/node_modules/request/node_modules/hawk/lib/index.js new file mode 100755 index 000000000..366cbf66d --- /dev/null +++ b/node_modules/request/node_modules/hawk/lib/index.js @@ -0,0 +1,11 @@ +// Export sub-modules + +exports.error = exports.Error = require('boom'); +exports.sntp = require('sntp'); +exports.server = require('./server'); +exports.client = require('./client'); +exports.uri = require('./uri'); +exports.crypto = require('./crypto'); +exports.utils = require('./utils'); + + diff --git a/node_modules/request/node_modules/hawk/lib/server.js b/node_modules/request/node_modules/hawk/lib/server.js new file mode 100755 index 000000000..c3005a685 --- /dev/null +++ b/node_modules/request/node_modules/hawk/lib/server.js @@ -0,0 +1,288 @@ +// Load modules + +var Boom = require('boom'); +var Hoek = require('hoek'); +var Cryptiles = require('cryptiles'); +var Crypto = require('./crypto'); +var Utils = require('./utils'); + + +// Declare internals + +var internals = {}; + + +// Hawk authentication + +/* + req: node's HTTP request object or an object as follows: + + var request = { + method: 'GET', + url: '/resource/4?a=1&b=2', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="' + }; + + credentialsFunc: required function to lookup the set of Hawk credentials based on the provided credentials id. + The credentials include the MAC key, MAC algorithm, and other attributes (such as username) + needed by the application. This function is the equivalent of verifying the username and + password in Basic authentication. + + var credentialsFunc = function (id, callback) { + + // Lookup credentials in database + db.lookup(id, function (err, item) { + + if (err || !item) { + return callback(err); + } + + var credentials = { + // Required + key: item.key, + algorithm: item.algorithm, + // Application specific + user: item.user + }; + + return callback(null, credentials); + }); + }; + + options: { + + hostHeaderName: optional header field name, used to override the default 'Host' header when used + behind a cache of a proxy. Apache2 changes the value of the 'Host' header while preserving + the original (which is what the module must verify) in the 'x-forwarded-host' header field. + Only used when passed a node Http.ServerRequest object. + + nonceFunc: optional nonce validation function. The function signature is function(nonce, ts, callback) + where 'callback' must be called using the signature function(err). + + timestampSkewSec: optional number of seconds of permitted clock skew for incoming timestamps. Defaults to 60 seconds. + Provides a +/- skew which means actual allowed window is double the number of seconds. + + localtimeOffsetMsec: optional local clock time offset express in a number of milliseconds (positive or negative). + Defaults to 0. + + payload: optional payload for validation. The client calculates the hash value and includes it via the 'hash' + header attribute. The server always ensures the value provided has been included in the request + MAC. When this option is provided, it validates the hash value itself. Validation is done by calculating + a hash value over the entire payload (assuming it has already be normalized to the same format and + encoding used by the client to calculate the hash on request). If the payload is not available at the time + of authentication, the authenticatePayload() method can be used by passing it the credentials and + attributes.hash returned in the authenticate callback. + } + + callback: function (err, credentials, artifacts) { } + */ + +exports.authenticate = function (req, credentialsFunc, options, callback) { + + // Default options + + options.nonceFunc = options.nonceFunc || function (nonce, ts, callback) { return callback(); }; // No validation + options.timestampSkewSec = options.timestampSkewSec || 60; // 60 seconds + + // Application time + + var now = Utils.now() + (options.localtimeOffsetMsec || 0); // Measure now before any other processing + + // Convert node Http request object to a request configuration object + + var request = Utils.parseRequest(req, options); + if (request instanceof Error) {
+ return callback(Boom.badRequest(request.message));
+ } + + // Parse HTTP Authorization header + + var attributes = Utils.parseAuthorizationHeader(request.authorization); + if (attributes instanceof Error) {
+ return callback(attributes);
+ } + + // Construct artifacts container + + var artifacts = {
+ method: request.method, + host: request.host, + port: request.port, + resource: request.url, + ts: attributes.ts, + nonce: attributes.nonce, + hash: attributes.hash, + ext: attributes.ext, + app: attributes.app, + dlg: attributes.dlg, + mac: attributes.mac, + id: attributes.id
+ }; + + // Verify required header attributes + + if (!attributes.id || + !attributes.ts || + !attributes.nonce || + !attributes.mac) {
+ + return callback(Boom.badRequest('Missing attributes'), null, artifacts);
+ } + + // Fetch Hawk credentials + + credentialsFunc(attributes.id, function (err, credentials) {
+ + artifacts.credentials = credentials; + + if (err) {
+ return callback(err, credentials || null, artifacts);
+ } + + if (!credentials) {
+ return callback(Boom.unauthorized('Unknown credentials', 'Hawk'), null, artifacts);
+ } + + if (!credentials.key || + !credentials.algorithm) {
+ + return callback(Boom.internal('Invalid credentials'), credentials, artifacts);
+ } + + if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return callback(Boom.internal('Unknown algorithm'), credentials, artifacts);
+ } + + // Calculate MAC + + var mac = Crypto.calculateMac('header', artifacts); + if (!Cryptiles.fixedTimeComparison(mac, attributes.mac)) {
+ return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials, artifacts);
+ } + + // Check payload hash + + if (options.payload !== null && + options.payload !== undefined) { // '' is valid + + if (!attributes.hash) {
+ return callback(Boom.unauthorized('Missing required payload hash', 'Hawk'), credentials, artifacts);
+ } + + var hash = Crypto.calculateHash(options.payload, credentials.algorithm, request.contentType); + if (!Cryptiles.fixedTimeComparison(hash, attributes.hash)) {
+ return callback(Boom.unauthorized('Bad payload hash', 'Hawk'), credentials, artifacts);
+ }
+ } + + // Check nonce + + options.nonceFunc(attributes.nonce, attributes.ts, function (err) {
+ + if (err) {
+ return callback(Boom.unauthorized('Invalid nonce', 'Hawk'), credentials, artifacts);
+ } + + // Check timestamp staleness + + if (Math.abs((attributes.ts * 1000) - now) > (options.timestampSkewSec * 1000)) {
+ var fresh = Utils.now() + (options.localtimeOffsetMsec || 0); // Get fresh now + var tsm = Crypto.calculateTsMac(fresh, credentials); + return callback(Boom.unauthorized('Stale timestamp', 'Hawk', { ts: fresh, tsm: tsm }), credentials, artifacts);
+ } + + // Successful authentication + + return callback(null, credentials, artifacts);
+ });
+ });
+}; + + +// Authenticate payload hash - used when payload cannot be provided during authenticate() + +/* + payload: raw request payload + credentials: from authenticate callback + hash: from authenticate callback (artifacts.hash) + contentType: req.headers['content-type'] +*/ + +exports.authenticatePayload = function (payload, credentials, hash, contentType) {
+ + var calculatedHash = Crypto.calculateHash(payload, credentials.algorithm, contentType); + return Cryptiles.fixedTimeComparison(calculatedHash, hash);
+}; + + +// Generate a Server-Authorization header for a given response + +/* + artifacts: {} // Object received from authenticate(); 'mac', 'hash', and 'ext' - ignored + options: { + ext: 'application-specific', // Application specific data sent via the ext attribute + payload: '{"some":"payload"}', // UTF-8 encoded string for body hash generation (ignored if hash provided) + contentType: 'application/json', // Payload content-type (ignored if hash provided) + hash: 'U4MKKSmiVxk37JCCrAVIjV=' // Pre-calculated payload hash + } +*/ + +exports.header = function (artifacts, options) { + + // Prepare inputs + + options = options || {}; + + if (!artifacts || + typeof artifacts !== 'object' || + typeof options !== 'object') {
+ + return '';
+ } + + artifacts = Hoek.clone(artifacts); + delete artifacts.mac; + artifacts.hash = options.hash; + artifacts.ext = options.ext; + + // Validate credentials + + var credentials = artifacts.credentials; + if (!credentials || + !credentials.key || + !credentials.algorithm) { + + // Invalid credential object + return '';
+ } + + if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) {
+ return '';
+ } + + // Calculate payload hash + + if (!artifacts.hash && + options.hasOwnProperty('payload')) {
+ + artifacts.hash = Crypto.calculateHash(options.payload, credentials.algorithm, options.contentType);
+ } + + var mac = Crypto.calculateMac('response', artifacts); + + // Construct header + + var header = 'Hawk mac="' + mac + '"' + + (artifacts.hash ? ', hash="' + artifacts.hash + '"' : ''); + + if (artifacts.ext !== null && + artifacts.ext !== undefined && + artifacts.ext !== '') { // Other falsey values allowed + + header += ', ext="' + Utils.escapeHeaderAttribute(artifacts.ext) + '"';
+ } + + return header;
+}; diff --git a/node_modules/request/node_modules/hawk/lib/uri.js b/node_modules/request/node_modules/hawk/lib/uri.js new file mode 100755 index 000000000..b247c331e --- /dev/null +++ b/node_modules/request/node_modules/hawk/lib/uri.js @@ -0,0 +1,238 @@ +// Load modules + +var Url = require('url'); +var Boom = require('boom'); +var Cryptiles = require('cryptiles'); +var Crypto = require('./crypto'); +var Utils = require('./utils'); + + +// Declare internals + +var internals = {}; + + +// Hawk authentication + +/* + * Arguments and options are the same as index.js with the exception that the only supported options are: + * 'hostHeaderName', 'localtimeOffsetMsec' + */ + +exports.authenticate = function (req, credentialsFunc, options, callback) { + + // Application time + + var now = Utils.now() + (options.localtimeOffsetMsec || 0); + + // Convert node Http request object to a request configuration object + + var request = Utils.parseRequest(req, options); + if (request instanceof Error) { + return callback(Boom.badRequest(request.message)); + } + + // Extract bewit + + // 1 2 3 4 + var resource = request.url.match(/^(\/.*)([\?&])bewit\=([^&$]*)(?:&(.+))?$/); + if (!resource) { + return callback(Boom.unauthorized(null, 'Hawk')); + } + + // Bewit not empty + + if (!resource[3]) { + return callback(Boom.unauthorized('Empty bewit', 'Hawk')); + } + + // Verify method is GET + + if (request.method !== 'GET' && + request.method !== 'HEAD') { + + return callback(Boom.unauthorized('Invalid method', 'Hawk')); + } + + // No other authentication + + if (request.authorization) { + return callback(Boom.badRequest('Multiple authentications', 'Hawk')); + } + + // Parse bewit + + var bewitString = Utils.base64urlDecode(resource[3]); + if (bewitString instanceof Error) { + return callback(Boom.badRequest('Invalid bewit encoding')); + } + + // Bewit format: id\exp\mac\ext ('\' is used because it is a reserved header attribute character) + + var bewitParts = bewitString.split('\\'); + if (!bewitParts || + bewitParts.length !== 4) { + + return callback(Boom.badRequest('Invalid bewit structure')); + } + + var bewit = { + id: bewitParts[0], + exp: parseInt(bewitParts[1], 10), + mac: bewitParts[2], + ext: bewitParts[3] || '' + }; + + if (!bewit.id || + !bewit.exp || + !bewit.mac) { + + return callback(Boom.badRequest('Missing bewit attributes')); + } + + // Construct URL without bewit + + var url = resource[1]; + if (resource[4]) { + url += resource[2] + resource[4]; + } + + // Check expiration + + if (bewit.exp * 1000 <= now) { + return callback(Boom.unauthorized('Access expired', 'Hawk'), null, bewit); + } + + // Fetch Hawk credentials + + credentialsFunc(bewit.id, function (err, credentials) { + + if (err) { + return callback(err, credentials || null, bewit.ext); + } + + if (!credentials) { + return callback(Boom.unauthorized('Unknown credentials', 'Hawk'), null, bewit); + } + + if (!credentials.key || + !credentials.algorithm) { + + return callback(Boom.internal('Invalid credentials'), credentials, bewit); + } + + if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) { + return callback(Boom.internal('Unknown algorithm'), credentials, bewit); + } + + // Calculate MAC + + var mac = Crypto.calculateMac('bewit', { + credentials: credentials, + ts: bewit.exp, + nonce: '', + method: 'GET', + resource: url, + host: request.host, + port: request.port, + ext: bewit.ext + }); + + if (!Cryptiles.fixedTimeComparison(mac, bewit.mac)) { + return callback(Boom.unauthorized('Bad mac', 'Hawk'), credentials, bewit); + } + + // Successful authentication + + return callback(null, credentials, bewit); + }); +}; + + +// Generate a bewit value for a given URI + +/* + * credentials is an object with the following keys: 'id, 'key', 'algorithm'. + * options is an object with the following optional keys: 'ext', 'localtimeOffsetMsec' + */ +/* + uri: 'http://example.com/resource?a=b' or object from Url.parse() + options: { + + // Required + + credentials: { + id: 'dh37fgj492je', + key: 'aoijedoaijsdlaksjdl', + algorithm: 'sha256' // 'sha1', 'sha256' + }, + ttlSec: 60 * 60, // TTL in seconds + + // Optional + + ext: 'application-specific', // Application specific data sent via the ext attribute + localtimeOffsetMsec: 400 // Time offset to sync with server time + }; +*/ + +exports.getBewit = function (uri, options) { + + // Validate inputs + + if (!uri || + (typeof uri !== 'string' && typeof uri !== 'object') || + !options || + typeof options !== 'object' || + !options.ttlSec) { + + return ''; + } + + options.ext = (options.ext === null || options.ext === undefined ? '' : options.ext); // Zero is valid value + + // Application time + + var now = Utils.now() + (options.localtimeOffsetMsec || 0); + + // Validate credentials + + var credentials = options.credentials; + if (!credentials || + !credentials.id || + !credentials.key || + !credentials.algorithm) { + + return ''; + } + + if (Crypto.algorithms.indexOf(credentials.algorithm) === -1) { + return ''; + } + + // Parse URI + + if (typeof uri === 'string') { + uri = Url.parse(uri); + } + + // Calculate signature + + var exp = Math.floor(now / 1000) + options.ttlSec; + var mac = Crypto.calculateMac('bewit', { + credentials: credentials, + ts: exp, + nonce: '', + method: 'GET', + resource: uri.pathname + (uri.search || ''), // Maintain trailing '?' + host: uri.hostname, + port: uri.port || (uri.protocol === 'http:' ? 80 : 443), + ext: options.ext + }); + + // Construct bewit: id\exp\mac\ext + + var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + options.ext; + return Utils.base64urlEncode(bewit); +}; + + diff --git a/node_modules/request/node_modules/hawk/lib/utils.js b/node_modules/request/node_modules/hawk/lib/utils.js new file mode 100755 index 000000000..ac9da401a --- /dev/null +++ b/node_modules/request/node_modules/hawk/lib/utils.js @@ -0,0 +1,167 @@ +// Load modules + +var Hoek = require('hoek'); +var Sntp = require('sntp'); +var Boom = require('boom'); + + +// Declare internals + +var internals = {}; + + +// Import Hoek Utilities + +internals.import = function () { + + for (var i in Hoek) { + if (Hoek.hasOwnProperty(i)) { + exports[i] = Hoek[i]; + } + } +}; + +internals.import(); + + +// Hawk version + +exports.version = function () { + + return exports.loadPackage(__dirname + '/..').version; +}; + + +// Extract host and port from request + +exports.parseHost = function (req, hostHeaderName) { + + hostHeaderName = (hostHeaderName ? hostHeaderName.toLowerCase() : 'host'); + var hostHeader = req.headers[hostHeaderName]; + if (!hostHeader) { + return null; + } + + var hostHeaderRegex = /^(?:(?:\r\n)?[\t ])*([^:]+)(?::(\d+))?(?:(?:\r\n)?[\t ])*$/; // Does not support IPv6 + var hostParts = hostHeader.match(hostHeaderRegex); + + if (!hostParts || + hostParts.length !== 3 || + !hostParts[1]) { + + return null; + } + + return { + name: hostParts[1], + port: (hostParts[2] ? hostParts[2] : (req.connection && req.connection.encrypted ? 443 : 80)) + }; +}; + + +// Parse Content-Type header content + +exports.parseContentType = function (header) {
+ + if (!header) {
+ return '';
+ } + + return header.split(';')[0].trim().toLowerCase(); +}; + + +// Convert node's to request configuration object + +exports.parseRequest = function (req, options) { + + if (!req.headers) { + return req; + } + + // Obtain host and port information + + var host = exports.parseHost(req, options.hostHeaderName); + if (!host) { + return new Error('Invalid Host header'); + } + + var request = { + method: req.method, + url: req.url, + host: host.name, + port: host.port, + authorization: req.headers.authorization, + contentType: req.headers['content-type'] || '' + }; + + return request; +}; + + +exports.now = function () { + + return Sntp.now(); +}; + + +// Parse Hawk HTTP Authorization header + +exports.parseAuthorizationHeader = function (header, keys) {
+ + keys = keys || ['id', 'ts', 'nonce', 'hash', 'ext', 'mac', 'app', 'dlg']; + + if (!header) {
+ return Boom.unauthorized(null, 'Hawk');
+ } + + var headerParts = header.match(/^(\w+)(?:\s+(.*))?$/); // Header: scheme[ something] + if (!headerParts) {
+ return Boom.badRequest('Invalid header syntax');
+ } + + var scheme = headerParts[1]; + if (scheme.toLowerCase() !== 'hawk') {
+ return Boom.unauthorized(null, 'Hawk');
+ } + + var attributesString = headerParts[2]; + if (!attributesString) {
+ return Boom.badRequest('Invalid header syntax');
+ } + + var attributes = {}; + var errorMessage = ''; + var verify = attributesString.replace(/(\w+)="([^"\\]*)"\s*(?:,\s*|$)/g, function ($0, $1, $2) { + + // Check valid attribute names + + if (keys.indexOf($1) === -1) {
+ errorMessage = 'Unknown attribute: ' + $1; + return;
+ } + + // Allowed attribute value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9 + + if ($2.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~]+$/) === null) {
+ errorMessage = 'Bad attribute value: ' + $1; + return;
+ } + + // Check for duplicates + + if (attributes.hasOwnProperty($1)) {
+ errorMessage = 'Duplicate attribute: ' + $1; + return;
+ } + + attributes[$1] = $2; + return '';
+ }); + + if (verify !== '') {
+ return Boom.badRequest(errorMessage || 'Bad header format');
+ }
+
+ return attributes;
+}; diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/.npmignore b/node_modules/request/node_modules/hawk/node_modules/boom/.npmignore new file mode 100644 index 000000000..77ba16cb0 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/.npmignore @@ -0,0 +1,18 @@ +.idea +*.iml +npm-debug.log +dump.rdb +node_modules +results.tap +results.xml +npm-shrinkwrap.json +config.json +.DS_Store +*/.DS_Store +*/*/.DS_Store +._* +*/._* +*/*/._* +coverage.* +lib-cov + diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/.travis.yml b/node_modules/request/node_modules/hawk/node_modules/boom/.travis.yml new file mode 100755 index 000000000..d8523c933 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/.travis.yml @@ -0,0 +1,5 @@ +language: node_js + +node_js: + - 0.8 + diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/LICENSE b/node_modules/request/node_modules/hawk/node_modules/boom/LICENSE new file mode 100755 index 000000000..911b97ee6 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2012-2013, Walmart. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Walmart nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL WALMART BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/Makefile b/node_modules/request/node_modules/hawk/node_modules/boom/Makefile new file mode 100755 index 000000000..9e7138c2a --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/Makefile @@ -0,0 +1,11 @@ +test: + @./node_modules/.bin/lab +test-cov: + @./node_modules/.bin/lab -r threshold -t 100 +test-cov-html: + @./node_modules/.bin/lab -r html -o coverage.html +complexity: + @./node_modules/.bin/cr -o complexity.md -f markdown lib + +.PHONY: test test-cov test-cov-html complexity + diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/README.md b/node_modules/request/node_modules/hawk/node_modules/boom/README.md new file mode 100755 index 000000000..1970b1c42 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/README.md @@ -0,0 +1,6 @@ +<a href="https://github.com/spumko"><img src="https://raw.github.com/spumko/spumko/master/images/from.png" align="right" /></a> +![boom Logo](https://raw.github.com/spumko/boom/master/images/boom.png) + +HTTP-friendly error objects + +[![Build Status](https://secure.travis-ci.org/spumko/boom.png)](http://travis-ci.org/spumko/boom) diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/images/boom.png b/node_modules/request/node_modules/hawk/node_modules/boom/images/boom.png Binary files differnew file mode 100755 index 000000000..373bc1345 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/images/boom.png diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/index.js b/node_modules/request/node_modules/hawk/node_modules/boom/index.js new file mode 100755 index 000000000..4cc88b358 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/index.js @@ -0,0 +1 @@ +module.exports = require('./lib');
\ No newline at end of file diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js b/node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js new file mode 100755 index 000000000..64d6b5309 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/lib/index.js @@ -0,0 +1,207 @@ +// Load modules
+
+var Http = require('http');
+var NodeUtil = require('util');
+var Hoek = require('hoek');
+
+
+// Declare internals
+
+var internals = {};
+
+
+exports = module.exports = internals.Boom = function (/* (new Error) or (code, message) */) {
+
+ var self = this;
+
+ Hoek.assert(this.constructor === internals.Boom, 'Error must be instantiated using new');
+
+ Error.call(this);
+ this.isBoom = true;
+
+ this.response = {
+ code: 0,
+ payload: {},
+ headers: {}
+ // type: 'content-type'
+ };
+
+ if (arguments[0] instanceof Error) {
+
+ // Error
+
+ var error = arguments[0];
+
+ this.data = error;
+ this.response.code = error.code || 500;
+ if (error.message) {
+ this.message = error.message;
+ }
+ }
+ else {
+
+ // code, message
+
+ var code = arguments[0];
+ var message = arguments[1];
+
+ Hoek.assert(!isNaN(parseFloat(code)) && isFinite(code) && code >= 400, 'First argument must be a number (400+)');
+
+ this.response.code = code;
+ if (message) {
+ this.message = message;
+ }
+ }
+
+ // Response format
+
+ this.reformat();
+
+ return this;
+};
+
+NodeUtil.inherits(internals.Boom, Error);
+
+
+internals.Boom.prototype.reformat = function () {
+
+ this.response.payload.code = this.response.code;
+ this.response.payload.error = Http.STATUS_CODES[this.response.code] || 'Unknown';
+ if (this.message) {
+ this.response.payload.message = Hoek.escapeHtml(this.message); // Prevent XSS from error message
+ }
+};
+
+
+// Utilities
+
+internals.Boom.badRequest = function (message) {
+
+ return new internals.Boom(400, message);
+};
+
+
+internals.Boom.unauthorized = function (error, scheme, attributes) { // Or function (error, wwwAuthenticate[])
+
+ var err = new internals.Boom(401, error);
+
+ if (!scheme) {
+ return err;
+ }
+
+ var wwwAuthenticate = '';
+
+ if (typeof scheme === 'string') {
+
+ // function (error, scheme, attributes)
+
+ wwwAuthenticate = scheme;
+ if (attributes) {
+ var names = Object.keys(attributes);
+ for (var i = 0, il = names.length; i < il; ++i) {
+ if (i) {
+ wwwAuthenticate += ',';
+ }
+
+ var value = attributes[names[i]];
+ if (value === null ||
+ value === undefined) { // Value can be zero
+
+ value = '';
+ }
+ wwwAuthenticate += ' ' + names[i] + '="' + Hoek.escapeHeaderAttribute(value.toString()) + '"';
+ }
+ }
+
+ if (error) {
+ if (attributes) {
+ wwwAuthenticate += ',';
+ }
+ wwwAuthenticate += ' error="' + Hoek.escapeHeaderAttribute(error) + '"';
+ }
+ else {
+ err.isMissing = true;
+ }
+ }
+ else {
+
+ // function (error, wwwAuthenticate[])
+
+ var wwwArray = scheme;
+ for (var i = 0, il = wwwArray.length; i < il; ++i) {
+ if (i) {
+ wwwAuthenticate += ', ';
+ }
+
+ wwwAuthenticate += wwwArray[i];
+ }
+ }
+
+ err.response.headers['WWW-Authenticate'] = wwwAuthenticate;
+
+ return err;
+};
+
+
+internals.Boom.clientTimeout = function (message) {
+
+ return new internals.Boom(408, message);
+};
+
+
+internals.Boom.serverTimeout = function (message) {
+
+ return new internals.Boom(503, message);
+};
+
+
+internals.Boom.forbidden = function (message) {
+
+ return new internals.Boom(403, message);
+};
+
+
+internals.Boom.notFound = function (message) {
+
+ return new internals.Boom(404, message);
+};
+
+
+internals.Boom.internal = function (message, data) {
+
+ var err = new internals.Boom(500, message);
+
+ if (data && data.stack) {
+ err.trace = data.stack.split('\n');
+ err.outterTrace = Hoek.displayStack(1);
+ }
+ else {
+ err.trace = Hoek.displayStack(1);
+ }
+
+ err.data = data;
+ err.response.payload.message = 'An internal server error occurred'; // Hide actual error from user
+
+ return err;
+};
+
+
+internals.Boom.passThrough = function (code, payload, contentType, headers) {
+
+ var err = new internals.Boom(500, 'Pass-through'); // 500 code is only used to initialize
+
+ err.data = {
+ code: code,
+ payload: payload,
+ type: contentType
+ };
+
+ err.response.code = code;
+ err.response.type = contentType;
+ err.response.headers = headers;
+ err.response.payload = payload;
+
+ return err;
+};
+
+
diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/package.json b/node_modules/request/node_modules/hawk/node_modules/boom/package.json new file mode 100755 index 000000000..97be2cae7 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/package.json @@ -0,0 +1,47 @@ +{ + "name": "boom", + "description": "HTTP-friendly error objects", + "version": "0.3.8", + "author": { + "name": "Eran Hammer", + "email": "eran@hueniverse.com", + "url": "http://hueniverse.com" + }, + "contributors": [], + "repository": { + "type": "git", + "url": "git://github.com/spumko/boom" + }, + "main": "index", + "keywords": [ + "error", + "http" + ], + "engines": { + "node": "0.8.x" + }, + "dependencies": { + "hoek": "0.7.x" + }, + "devDependencies": { + "lab": "0.0.x", + "complexity-report": "0.x.x" + }, + "scripts": { + "test": "make test-cov" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/spumko/boom/raw/master/LICENSE" + } + ], + "readme": "<a href=\"https://github.com/spumko\"><img src=\"https://raw.github.com/spumko/spumko/master/images/from.png\" align=\"right\" /></a>\n![boom Logo](https://raw.github.com/spumko/boom/master/images/boom.png)\n\nHTTP-friendly error objects\n\n[![Build Status](https://secure.travis-ci.org/spumko/boom.png)](http://travis-ci.org/spumko/boom)\n", + "readmeFilename": "README.md", + "_id": "boom@0.3.8", + "dist": { + "shasum": "1aaf60284b7b0e0dab42ceb8e27afd0e4ab61cdf" + }, + "_from": "boom@0.3.x", + "_resolved": "https://registry.npmjs.org/boom/-/boom-0.3.8.tgz" +} diff --git a/node_modules/request/node_modules/hawk/node_modules/boom/test/index.js b/node_modules/request/node_modules/hawk/node_modules/boom/test/index.js new file mode 100755 index 000000000..02a178674 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/boom/test/index.js @@ -0,0 +1,245 @@ +// Load modules
+
+var Lab = require('lab');
+var Boom = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Boom', function () {
+
+ it('returns an error with info when constructed using another error', function (done) {
+
+ var error = new Error('ka-boom');
+ error.xyz = 123;
+ var err = new Boom(error);
+ expect(err.data.xyz).to.equal(123);
+ expect(err.message).to.equal('ka-boom');
+ expect(err.response).to.deep.equal({
+ code: 500,
+ payload: {
+ code: 500,
+ error: 'Internal Server Error',
+ message: 'ka-boom'
+ },
+ headers: {}
+ });
+ done();
+ });
+
+ describe('#isBoom', function () {
+
+ it('returns true for Boom object', function (done) {
+
+ expect(Boom.badRequest().isBoom).to.equal(true);
+ done();
+ });
+
+ it('returns false for Error object', function (done) {
+
+ expect(new Error().isBoom).to.not.exist;
+ done();
+ });
+ });
+
+ describe('#badRequest', function () {
+
+ it('returns a 400 error code', function (done) {
+
+ expect(Boom.badRequest().response.code).to.equal(400);
+ done();
+ });
+
+ it('sets the message with the passed in message', function (done) {
+
+ expect(Boom.badRequest('my message').message).to.equal('my message');
+ done();
+ });
+ });
+
+ describe('#unauthorized', function () {
+
+ it('returns a 401 error code', function (done) {
+
+ var err = Boom.unauthorized();
+ expect(err.response.code).to.equal(401);
+ expect(err.response.headers).to.deep.equal({});
+ done();
+ });
+
+ it('sets the message with the passed in message', function (done) {
+
+ expect(Boom.unauthorized('my message').message).to.equal('my message');
+ done();
+ });
+
+ it('returns a WWW-Authenticate header when passed a scheme', function (done) {
+
+ var err = Boom.unauthorized('boom', 'Test');
+ expect(err.response.code).to.equal(401);
+ expect(err.response.headers['WWW-Authenticate']).to.equal('Test error="boom"');
+ done();
+ });
+
+ it('returns a WWW-Authenticate header when passed a scheme and attributes', function (done) {
+
+ var err = Boom.unauthorized('boom', 'Test', { a: 1, b: 'something', c: null, d: 0 });
+ expect(err.response.code).to.equal(401);
+ expect(err.response.headers['WWW-Authenticate']).to.equal('Test a="1", b="something", c="", d="0", error="boom"');
+ done();
+ });
+
+ it('sets the isMissing flag when error message is empty', function (done) {
+
+ var err = Boom.unauthorized('', 'Basic');
+ expect(err.isMissing).to.equal(true);
+ done();
+ });
+
+ it('does not set the isMissing flag when error message is not empty', function (done) {
+
+ var err = Boom.unauthorized('message', 'Basic');
+ expect(err.isMissing).to.equal(undefined);
+ done();
+ });
+
+ it('sets a WWW-Authenticate when passed as an array', function (done) {
+
+ var err = Boom.unauthorized('message', ['Basic', 'Example e="1"', 'Another x="3", y="4"']);
+ expect(err.response.headers['WWW-Authenticate']).to.equal('Basic, Example e="1", Another x="3", y="4"');
+ done();
+ });
+ });
+
+ describe('#clientTimeout', function () {
+
+ it('returns a 408 error code', function (done) {
+
+ expect(Boom.clientTimeout().response.code).to.equal(408);
+ done();
+ });
+
+ it('sets the message with the passed in message', function (done) {
+
+ expect(Boom.clientTimeout('my message').message).to.equal('my message');
+ done();
+ });
+ });
+
+ describe('#serverTimeout', function () {
+
+ it('returns a 503 error code', function (done) {
+
+ expect(Boom.serverTimeout().response.code).to.equal(503);
+ done();
+ });
+
+ it('sets the message with the passed in message', function (done) {
+
+ expect(Boom.serverTimeout('my message').message).to.equal('my message');
+ done();
+ });
+ });
+
+ describe('#forbidden', function () {
+
+ it('returns a 403 error code', function (done) {
+
+ expect(Boom.forbidden().response.code).to.equal(403);
+ done();
+ });
+
+ it('sets the message with the passed in message', function (done) {
+
+ expect(Boom.forbidden('my message').message).to.equal('my message');
+ done();
+ });
+ });
+
+ describe('#notFound', function () {
+
+ it('returns a 404 error code', function (done) {
+
+ expect(Boom.notFound().response.code).to.equal(404);
+ done();
+ });
+
+ it('sets the message with the passed in message', function (done) {
+
+ expect(Boom.notFound('my message').message).to.equal('my message');
+ done();
+ });
+ });
+
+ describe('#internal', function () {
+
+ it('returns a 500 error code', function (done) {
+
+ expect(Boom.internal().response.code).to.equal(500);
+ done();
+ });
+
+ it('sets the message with the passed in message', function (done) {
+
+ var err = Boom.internal('my message');
+ expect(err.message).to.equal('my message');
+ expect(err.response.payload.message).to.equal('An internal server error occurred');
+ done();
+ });
+
+ it('passes data on the callback if its passed in', function (done) {
+
+ expect(Boom.internal('my message', { my: 'data' }).data.my).to.equal('data');
+ done();
+ });
+
+ it('uses passed in stack if its available', function (done) {
+
+ var error = new Error();
+ error.stack = 'my stack line\nmy second stack line';
+ expect(Boom.internal('my message', error).trace[0]).to.equal('my stack line');
+ done();
+ });
+ });
+
+ describe('#passThrough', function () {
+
+ it('returns a pass-through error', function (done) {
+
+ var err = Boom.passThrough(499, { a: 1 }, 'application/text', { 'X-Test': 'Boom' });
+ expect(err.response.code).to.equal(499);
+ expect(err.message).to.equal('Pass-through');
+ expect(err.response).to.deep.equal({
+ code: 499,
+ payload: { a: 1 },
+ headers: { 'X-Test': 'Boom' },
+ type: 'application/text'
+ });
+ done();
+ });
+ });
+
+ describe('#reformat', function () {
+
+ it('encodes any HTML markup in the response payload', function (done) {
+
+ var boom = new Boom(new Error('<script>alert(1)</script>'));
+ expect(boom.response.payload.message).to.not.contain('<script>');
+ done();
+ });
+ });
+});
+
+
diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/.npmignore b/node_modules/request/node_modules/hawk/node_modules/cryptiles/.npmignore new file mode 100644 index 000000000..77ba16cb0 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/.npmignore @@ -0,0 +1,18 @@ +.idea +*.iml +npm-debug.log +dump.rdb +node_modules +results.tap +results.xml +npm-shrinkwrap.json +config.json +.DS_Store +*/.DS_Store +*/*/.DS_Store +._* +*/._* +*/*/._* +coverage.* +lib-cov + diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/.travis.yml b/node_modules/request/node_modules/hawk/node_modules/cryptiles/.travis.yml new file mode 100755 index 000000000..d8523c933 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/.travis.yml @@ -0,0 +1,5 @@ +language: node_js + +node_js: + - 0.8 + diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/LICENSE b/node_modules/request/node_modules/hawk/node_modules/cryptiles/LICENSE new file mode 100755 index 000000000..e699a7bdb --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2012-2013, Eran Hammer. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Eran Hammer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ERAN HAMMER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/Makefile b/node_modules/request/node_modules/hawk/node_modules/cryptiles/Makefile new file mode 100755 index 000000000..97ba3af43 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/Makefile @@ -0,0 +1,11 @@ +test:
+ @./node_modules/.bin/lab
+test-cov:
+ @./node_modules/.bin/lab -r threshold -t 100
+test-cov-html:
+ @./node_modules/.bin/lab -r html -o coverage.html
+complexity:
+ @./node_modules/.bin/cr -o complexity.md -f markdown lib
+
+.PHONY: test test-cov test-cov-html complexity
+
diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/README.md b/node_modules/request/node_modules/hawk/node_modules/cryptiles/README.md new file mode 100644 index 000000000..6a900a491 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/README.md @@ -0,0 +1,6 @@ +cryptiles +========= + +General purpose crypto utilities + +[![Build Status](https://secure.travis-ci.org/hueniverse/cryptiles.png)](http://travis-ci.org/hueniverse/cryptiles) diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/index.js b/node_modules/request/node_modules/hawk/node_modules/cryptiles/index.js new file mode 100755 index 000000000..4cc88b358 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/index.js @@ -0,0 +1 @@ +module.exports = require('./lib');
\ No newline at end of file diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js b/node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js new file mode 100755 index 000000000..4a3773681 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/lib/index.js @@ -0,0 +1,62 @@ +// Load modules + +var Crypto = require('crypto'); +var Boom = require('boom'); + + +// Declare internals + +var internals = {}; + + +// Generate a cryptographically strong pseudo-random data + +exports.randomString = function (size) { + + var buffer = exports.randomBits((size + 1) * 6); + if (buffer instanceof Error) { + return buffer; + } + + var string = buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, ''); + return string.slice(0, size); +}; + + +exports.randomBits = function (bits) { + + if (!bits || + bits < 0) { + + return Boom.internal('Invalid random bits count'); + } + + var bytes = Math.ceil(bits / 8); + try { + return Crypto.randomBytes(bytes); + } + catch (err) { + return Boom.internal('Failed generating random bits: ' + err.message); + } +}; + + +// Compare two strings using fixed time algorithm (to prevent time-based analysis of MAC digest match) + +exports.fixedTimeComparison = function (a, b) { + + var mismatch = (a.length === b.length ? 0 : 1); + if (mismatch) { + b = a; + } + + for (var i = 0, il = a.length; i < il; ++i) { + var ac = a.charCodeAt(i); + var bc = b.charCodeAt(i); + mismatch += (ac === bc ? 0 : 1); + } + + return (mismatch === 0); +}; + + diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/package.json b/node_modules/request/node_modules/hawk/node_modules/cryptiles/package.json new file mode 100755 index 000000000..7a331d968 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/package.json @@ -0,0 +1,48 @@ +{ + "name": "cryptiles", + "description": "General purpose crypto utilities", + "version": "0.1.3", + "author": { + "name": "Eran Hammer", + "email": "eran@hueniverse.com", + "url": "http://hueniverse.com" + }, + "contributors": [], + "repository": { + "type": "git", + "url": "git://github.com/hueniverse/cryptiles" + }, + "main": "index", + "keywords": [ + "cryptography", + "security", + "utilites" + ], + "engines": { + "node": "0.8.x" + }, + "dependencies": { + "boom": "0.3.x" + }, + "devDependencies": { + "lab": "0.0.x", + "complexity-report": "0.x.x" + }, + "scripts": { + "test": "make test-cov" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/hueniverse/cryptiles/raw/master/LICENSE" + } + ], + "readme": "cryptiles\n=========\n\nGeneral purpose crypto utilities\n\n[![Build Status](https://secure.travis-ci.org/hueniverse/cryptiles.png)](http://travis-ci.org/hueniverse/cryptiles)\n", + "readmeFilename": "README.md", + "_id": "cryptiles@0.1.3", + "dist": { + "shasum": "dfc70d32f10b0a09654ab8bac5fc659b36dd73f1" + }, + "_from": "cryptiles@0.1.x", + "_resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.1.3.tgz" +} diff --git a/node_modules/request/node_modules/hawk/node_modules/cryptiles/test/index.js b/node_modules/request/node_modules/hawk/node_modules/cryptiles/test/index.js new file mode 100755 index 000000000..128be1088 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/cryptiles/test/index.js @@ -0,0 +1,95 @@ +// Load modules + +var Lab = require('lab');
+var Cryptiles = require('../lib'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+ + +describe('Cryptiles', function () { + + describe('#randomString', function () { + + it('should generate the right length string', function (done) { + + for (var i = 1; i <= 1000; ++i) { + expect(Cryptiles.randomString(i).length).to.equal(i); + } + + done(); + }); + + it('returns an error on invalid bits size', function (done) { + + expect(Cryptiles.randomString(99999999999999999999).message).to.equal('Failed generating random bits: Argument #1 must be number > 0'); + done(); + }); + }); + + describe('#randomBits', function () { + + it('returns an error on invalid input', function (done) { + + expect(Cryptiles.randomBits(0).message).to.equal('Invalid random bits count'); + done(); + }); + }); + + describe('#fixedTimeComparison', function () { + + var a = Cryptiles.randomString(50000); + var b = Cryptiles.randomString(150000); + + it('should take the same amount of time comparing different string sizes', function (done) { + + var now = Date.now(); + Cryptiles.fixedTimeComparison(b, a); + var t1 = Date.now() - now; + + now = Date.now(); + Cryptiles.fixedTimeComparison(b, b); + var t2 = Date.now() - now; + + expect(t2 - t1).to.be.within(-20, 20); + done(); + }); + + it('should return true for equal strings', function (done) { + + expect(Cryptiles.fixedTimeComparison(a, a)).to.equal(true); + done(); + }); + + it('should return false for different strings (size, a < b)', function (done) { + + expect(Cryptiles.fixedTimeComparison(a, a + 'x')).to.equal(false); + done(); + }); + + it('should return false for different strings (size, a > b)', function (done) { + + expect(Cryptiles.fixedTimeComparison(a + 'x', a)).to.equal(false); + done(); + }); + + it('should return false for different strings (size, a = b)', function (done) { + + expect(Cryptiles.fixedTimeComparison(a + 'x', a + 'y')).to.equal(false); + done(); + }); + }); +}); + + diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/.npmignore b/node_modules/request/node_modules/hawk/node_modules/hoek/.npmignore new file mode 100644 index 000000000..9966e5e63 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/.npmignore @@ -0,0 +1,18 @@ +.idea
+*.iml
+npm-debug.log
+dump.rdb
+node_modules
+results.tap
+results.xml
+npm-shrinkwrap.json
+config.json
+.DS_Store
+*/.DS_Store
+*/*/.DS_Store
+._*
+*/._*
+*/*/._*
+coverage.*
+lib-cov
+complexity.md
diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/.travis.yml b/node_modules/request/node_modules/hawk/node_modules/hoek/.travis.yml new file mode 100755 index 000000000..d8523c933 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/.travis.yml @@ -0,0 +1,5 @@ +language: node_js + +node_js: + - 0.8 + diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/LICENSE b/node_modules/request/node_modules/hawk/node_modules/hoek/LICENSE new file mode 100755 index 000000000..87c1f4e11 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/LICENSE @@ -0,0 +1,33 @@ +Copyright (c) 2011-2013, Walmart. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Walmart nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL WALMART BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + * * * + + +Portions of this project were initially based on Postmile, Copyright (c) 2011, Yahoo Inc. +Postmile is published at https://github.com/yahoo/postmile and its licensing terms are +published at https://github.com/yahoo/postmile/blob/master/LICENSE. + diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/Makefile b/node_modules/request/node_modules/hawk/node_modules/hoek/Makefile new file mode 100755 index 000000000..48ee48e73 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/Makefile @@ -0,0 +1,10 @@ +test: + @./node_modules/.bin/lab +test-cov: + @./node_modules/.bin/lab -r threshold -t 100 +test-cov-html: + @./node_modules/.bin/lab -r html -o coverage.html +complexity: + @./node_modules/.bin/cr -o complexity.md -f markdown lib + +.PHONY: test test-cov test-cov-html complexity
\ No newline at end of file diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/README.md b/node_modules/request/node_modules/hawk/node_modules/hoek/README.md new file mode 100755 index 000000000..4e75403e2 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/README.md @@ -0,0 +1,436 @@ +<a href="https://github.com/spumko"><img src="https://raw.github.com/spumko/spumko/master/images/from.png" align="right" /></a> +![hoek Logo](https://raw.github.com/spumko/hoek/master/images/hoek.png) + +General purpose node utilities + +[![Build Status](https://secure.travis-ci.org/spumko/hoek.png)](http://travis-ci.org/spumko/hoek) + +# Table of Contents + +* [Introduction](#introduction "Introduction") +* [Object](#object "Object") + * [clone](#cloneobj "clone") + * [merge](#mergetarget-source-isnulloverride-ismergearrays "merge") + * [applyToDefaults](#applytodefaultsdefaults-options "applyToDefaults") + * [unique](#uniquearray-key "unique") + * [mapToObject](#maptoobjectarray-key "mapToObject") + * [intersect](#intersectarray1-array2 "intersect") + * [matchKeys](#matchkeysobj-keys "matchKeys") + * [flatten](#flattenarray-target "flatten") + * [removeKeys](#removekeysobject-keys "removeKeys") + * [reach](#reachobj-chain "reach") + * [inheritAsync](#inheritasyncself-obj-keys "inheritAsync") + * [rename](#renameobj-from-to "rename") +* [Timer](#timer "Timer") +* [Binary Encoding/Decoding](#binary "Binary Encoding/Decoding") + * [base64urlEncode](#binary64urlEncodevalue "binary64urlEncode") + * [base64urlDecode](#binary64urlDecodevalue "binary64urlDecode") +* [Escaping Characters](#escaped "Escaping Characters") + * [escapeHtml](#escapeHtmlstring "escapeHtml") + * [escapeHeaderAttribute](#escapeHeaderAttributeattribute "escapeHeaderAttribute") + * [escapeRegex](#escapeRegexstring "escapeRegex") +* [Errors](#errors "Errors") + * [assert](#assertmessage "assert") + * [abort](#abortmessage "abort") + * [displayStack](#displayStackslice "displayStack") + * [callStack](#callStackslice "callStack") + * [toss](#tosscondition "toss") +* [Load files](#load-files "Load Files") + * [loadPackage](#loadPackagedir "loadpackage") + * [loadDirModules](#loadDirModulespath-excludefiles-target "loaddirmodules") + + + +# Introduction + +The *Hoek* general purpose node utilities library is used to aid in a variety of manners. It comes with useful methods for Ararys (clone, merge, applyToDefaults), Objects (removeKeys, copy), Asserting and more. + +For example, to use Hoek to set configuration with default options: +```javascript +var Hoek = require('hoek'); + +var default = {url : "www.github.com", port : "8000", debug : true} + +var config = Hoek.applyToDefaults(default, {port : "3000", admin : true}); + +// In this case, config would be { url: 'www.github.com', port: '3000', debug: true, admin: true } +``` + +Under each of the sections (such as Array), there are subsections which correspond to Hoek methods. Each subsection will explain how to use the corresponding method. In each js excerpt below, the var Hoek = require('hoek') is omitted for brevity. + +## Object + +Hoek provides several helpful methods for objects and arrays. + +### clone(obj) + +This method is used to clone an object or an array. A *deep copy* is made (duplicates everything, including values that are objects). + +```javascript + +var nestedObj = { + w: /^something$/ig, + x: { + a: [1, 2, 3], + b: 123456, + c: new Date() + }, + y: 'y', + z: new Date() + }; + +var copy = Hoek.clone(nestedObj); + +copy.x.b = 100; + +console.log(copy.y) // results in 'y' +console.log(nestedObj.x.b) // results in 123456 +console.log(copy.x.b) // results in 100 +``` + +### merge(target, source, isNullOverride, isMergeArrays) +isNullOverride, isMergeArrays default to true + +Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied + + +```javascript + +var target = {a: 1, b : 2} +var source = {a: 0, c: 5} +var source2 = {a: null, c: 5} + +var targetArray = [1, 2, 3]; +var sourceArray = [4, 5]; + +var newTarget = Hoek.merge(target, source); // results in {a: 0, b: 2, c: 5} +newTarget = Hoek.merge(target, source2); // results in {a: null, b: 2, c: 5} +newTarget = Hoek.merge(target, source2, false); // results in {a: null, b:2, c: 5} + +newTarget = Hoek.merge(targetArray, sourceArray) // results in [1, 2, 3, 4, 5] +newTarget = Hoek.merge(targetArray, sourceArray, true, false) // results in [4, 5] + + + + +``` + +### applyToDefaults(defaults, options) + +Apply options to a copy of the defaults + +```javascript + +var defaults = {host: "localhost", port: 8000}; +var options = {port: 8080}; + +var config = Hoek.applyToDefaults(defaults, options); // results in {host: "localhost", port: 8080}; + + +``` + +### unique(array, key) + +Remove duplicate items from Array + +```javascript + +var array = [1, 2, 2, 3, 3, 4, 5, 6]; + +var newArray = Hoek.unique(array); // results in [1,2,3,4,5,6]; + +array = [{id: 1}, {id: 1}, {id: 2}]; + +newArray = Hoek.unique(array, "id") // results in [{id: 1}, {id: 2}] + +``` + +### mapToObject(array, key) + +Convert an Array into an Object + +```javascript + +var array = [1,2,3]; +var newObject = Hoek.mapToObject(array); // results in [{"1": true}, {"2": true}, {"3": true}] + +array = [{id: 1}, {id: 2}]; +newObject = Hoek.mapToObject(array, "id") // results in [{"id": 1}, {"id": 2}] + +``` +### intersect(array1, array2) + +Find the common unique items in two arrays + +```javascript + +var array1 = [1, 2, 3]; +var array2 = [1, 4, 5]; + +var newArray = Hoek.intersect(array1, array2) // results in [1] + +``` + +### matchKeys(obj, keys) + +Find which keys are present + +```javascript + +var obj = {a: 1, b: 2, c: 3}; +var keys = ["a", "e"]; + +Hoek.matchKeys(obj, keys) // returns ["a"] + +``` + +### flatten(array, target) + +Flatten an array + +```javascript + +var array = [1, 2, 3]; +var target = [4, 5]; + +var flattenedArray = Hoek.flatten(array, target) // results in [4, 5, 1, 2, 3]; + +``` + +### removeKeys(object, keys) + +Remove keys + +```javascript + +var object = {a: 1, b: 2, c: 3, d: 4}; + +var keys = ["a", "b"]; + +Hoek.removeKeys(object, keys) // object is now {c: 3, d: 4} + +``` + +### reach(obj, chain) + +Converts an object key chain string to reference + +```javascript + +var chain = 'a.b.c'; +var obj = {a : {b : { c : 1}}}; + +Hoek.reach(obj, chain) // returns 1 + +``` + +### inheritAsync(self, obj, keys) + +Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors + +```javascript + +var targetFunc = function () { }; + +var proto = { + a: function () { + return 'a!'; + }, + b: function () { + return 'b!'; + }, + c: function () { + throw new Error('c!'); + } + }; + +var keys = ['a', 'c']; + +Hoek.inheritAsync(targetFunc, proto, ['a', 'c']); + +var target = new targetFunc(); + +target.a(function(err, result){console.log(result)} // returns 'a!' + +target.c(function(err, result){console.log(result)} // returns undefined + +target.b(function(err, result){console.log(result)} // gives error: Object [object Object] has no method 'b' + +``` + +### rename(obj, from, to) + +Rename a key of an object + +```javascript + +var obj = {a : 1, b : 2}; + +Hoek.rename(obj, "a", "c"); // obj is now {c : 1, b : 2} + +``` + + +# Timer + +A Timer object. Initializing a new timer object sets the ts to the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC. + +```javascript + + +example : + + +var timerObj = new Hoek.Timer(); +console.log("Time is now: " + timerObj.ts) +console.log("Elapsed time from initialization: " + timerObj.elapsed() + 'milliseconds') + +``` + +# Binary Encoding/Decoding + +### base64urlEncode(value) + +Encodes value in Base64 or URL encoding + +### base64urlDecode(value) + +Decodes data in Base64 or URL encoding. +# Escaping Characters + +Hoek provides convenient methods for escaping html characters. The escaped characters are as followed: + +```javascript + +internals.htmlEscaped = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' +}; + +``` + +### escapeHtml(string) + +```javascript + +var string = '<html> hey </html>'; +var escapedString = Hoek.escapeHtml(string); // returns <html> hey </html> + +``` + +### escapeHeaderAttribute(attribute) + +Escape attribute value for use in HTTP header + +```javascript + +var a = Hoek.escapeHeaderAttribute('I said "go w\\o me"'); //returns I said \"go w\\o me\" + + +``` + + +### escapeRegex(string) + +Escape string for Regex construction + +```javascript + +var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,'); // returns 4\^f\$s\.4\*5\+\-_\?%\=#\!\:@\|~\\\/`"\(>\)\[<\]d\{\}s\, + + + +``` + +# Errors + +### assert(message) + +```javascript + +var a = 1, b =2; + +Hoek.assert(a === b, 'a should equal b'); // ABORT: a should equal b + +``` + +### abort(message) + +First checks if process.env.NODE_ENV === 'test', and if so, throws error message. Otherwise, +displays most recent stack and then exits process. + + + +### displayStack(slice) + +Displays the trace stack + +```javascript + +var stack = Hoek.displayStack(); +console.log(stack) // returns something like: + +[ 'null (/Users/user/Desktop/hoek/test.js:4:18)', + 'Module._compile (module.js:449:26)', + 'Module._extensions..js (module.js:467:10)', + 'Module.load (module.js:356:32)', + 'Module._load (module.js:312:12)', + 'Module.runMain (module.js:492:10)', + 'startup.processNextTick.process._tickCallback (node.js:244:9)' ] + +``` + +### callStack(slice) + +Returns a trace stack array. + +```javascript + +var stack = Hoek.callStack(); +console.log(stack) // returns something like: + +[ [ '/Users/user/Desktop/hoek/test.js', 4, 18, null, false ], + [ 'module.js', 449, 26, 'Module._compile', false ], + [ 'module.js', 467, 10, 'Module._extensions..js', false ], + [ 'module.js', 356, 32, 'Module.load', false ], + [ 'module.js', 312, 12, 'Module._load', false ], + [ 'module.js', 492, 10, 'Module.runMain', false ], + [ 'node.js', + 244, + 9, + 'startup.processNextTick.process._tickCallback', + false ] ] + + +``` + +### toss(condition) + +toss(condition /*, [message], callback */) + +Return an error as first argument of a callback + + +# Load Files + +### loadPackage(dir) + +Load and parse package.json process root or given directory + +```javascript + +var pack = Hoek.loadPackage(); // pack.name === 'hoek' + +``` + +### loadDirModules(path, excludeFiles, target) + +Loads modules from a given path; option to exclude files (array). + + + + diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/images/hoek.png b/node_modules/request/node_modules/hawk/node_modules/hoek/images/hoek.png Binary files differnew file mode 100755 index 000000000..6ccfcb12b --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/images/hoek.png diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/index.js b/node_modules/request/node_modules/hawk/node_modules/hoek/index.js new file mode 100755 index 000000000..4cc88b358 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/index.js @@ -0,0 +1 @@ +module.exports = require('./lib');
\ No newline at end of file diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js b/node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js new file mode 100755 index 000000000..666b3dc82 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/lib/escape.js @@ -0,0 +1,132 @@ +// Declare internals
+
+var internals = {};
+
+
+exports.escapeJavaScript = function (input) {
+
+ if (!input) {
+ return '';
+ }
+
+ var escaped = '';
+
+ for (var i = 0, il = input.length; i < il; ++i) {
+
+ var charCode = input.charCodeAt(i);
+
+ if (internals.isSafe(charCode)) {
+ escaped += input[i];
+ }
+ else {
+ escaped += internals.escapeJavaScriptChar(charCode);
+ }
+ }
+
+ return escaped;
+};
+
+
+exports.escapeHtml = function (input) {
+
+ if (!input) {
+ return '';
+ }
+
+ var escaped = '';
+
+ for (var i = 0, il = input.length; i < il; ++i) {
+
+ var charCode = input.charCodeAt(i);
+
+ if (internals.isSafe(charCode)) {
+ escaped += input[i];
+ }
+ else {
+ escaped += internals.escapeHtmlChar(charCode);
+ }
+ }
+
+ return escaped;
+};
+
+
+internals.escapeJavaScriptChar = function (charCode) {
+
+ if (charCode >= 256) {
+ return '\\u' + internals.padLeft('' + charCode, 4);
+ }
+
+ var hexValue = new Buffer(String.fromCharCode(charCode), 'ascii').toString('hex');
+ return '\\x' + internals.padLeft(hexValue, 2);
+};
+
+
+internals.escapeHtmlChar = function (charCode) {
+
+ var namedEscape = internals.namedHtml[charCode];
+ if (typeof namedEscape !== 'undefined') {
+ return namedEscape;
+ }
+
+ if (charCode >= 256) {
+ return '&#' + charCode + ';';
+ }
+
+ var hexValue = new Buffer(String.fromCharCode(charCode), 'ascii').toString('hex');
+ return '&#x' + internals.padLeft(hexValue, 2) + ';';
+};
+
+
+internals.padLeft = function (str, len) {
+
+ while (str.length < len) {
+ str = '0' + str;
+ }
+
+ return str;
+};
+
+
+internals.isSafe = function (charCode) {
+
+ return (typeof internals.safeCharCodes[charCode] !== 'undefined');
+};
+
+
+internals.namedHtml = {
+ '38': '&',
+ '60': '<',
+ '62': '>',
+ '34': '"',
+ '160': ' ',
+ '162': '¢',
+ '163': '£',
+ '164': '¤',
+ '169': '©',
+ '174': '®'
+};
+
+
+internals.safeCharCodes = (function () {
+
+ var safe = {};
+
+ for (var i = 32; i < 123; ++i) {
+
+ if ((i >= 97 && i <= 122) || // a-z
+ (i >= 65 && i <= 90) || // A-Z
+ (i >= 48 && i <= 57) || // 0-9
+ i === 32 || // space
+ i === 46 || // .
+ i === 44 || // ,
+ i === 45 || // -
+ i === 58 || // :
+ i === 95) { // _
+
+ safe[i] = null;
+ }
+ }
+
+ return safe;
+}());
\ No newline at end of file diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js b/node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js new file mode 100755 index 000000000..de35a6203 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/lib/index.js @@ -0,0 +1,557 @@ +// Load modules
+
+var Fs = require('fs');
+var Escape = require('./escape');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Clone object or array
+
+exports.clone = function (obj, seen) {
+
+ if (typeof obj !== 'object' ||
+ obj === null) {
+
+ return obj;
+ }
+
+ seen = seen || { orig: [], copy: [] };
+
+ var lookup = seen.orig.indexOf(obj);
+ if (lookup !== -1) {
+ return seen.copy[lookup];
+ }
+
+ var newObj = (obj instanceof Array) ? [] : {};
+
+ seen.orig.push(obj);
+ seen.copy.push(newObj);
+
+ for (var i in obj) {
+ if (obj.hasOwnProperty(i)) {
+ if (obj[i] instanceof Date) {
+ newObj[i] = new Date(obj[i].getTime());
+ }
+ else if (obj[i] instanceof RegExp) {
+ var flags = '' + (obj[i].global ? 'g' : '') + (obj[i].ignoreCase ? 'i' : '') + (obj[i].multiline ? 'm' : '');
+ newObj[i] = new RegExp(obj[i].source, flags);
+ }
+ else {
+ newObj[i] = exports.clone(obj[i], seen);
+ }
+ }
+ }
+
+ return newObj;
+};
+
+
+// Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied
+
+exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {
+
+ exports.assert(target && typeof target == 'object', 'Invalid target value: must be an object');
+ exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
+
+ if (!source) {
+ return target;
+ }
+
+ if (source instanceof Array) {
+ exports.assert(target instanceof Array, 'Cannot merge array onto an object');
+ if (isMergeArrays === false) { // isMergeArrays defaults to true
+ target.length = 0; // Must not change target assignment
+ }
+
+ source.forEach(function (item) {
+
+ target.push(item);
+ });
+
+ return target;
+ }
+
+ Object.keys(source).forEach(function (key) {
+
+ var value = source[key];
+ if (value &&
+ typeof value === 'object') {
+
+ if (!target[key] ||
+ typeof target[key] !== 'object') {
+
+ target[key] = exports.clone(value);
+ }
+ else {
+ exports.merge(target[key], source[key], isNullOverride, isMergeArrays);
+ }
+ }
+ else {
+ if (value !== null && value !== undefined) { // Explicit to preserve empty strings
+ target[key] = value;
+ }
+ else if (isNullOverride !== false) { // Defaults to true
+ target[key] = value;
+ }
+ }
+ });
+
+ return target;
+};
+
+
+// Apply options to a copy of the defaults
+
+exports.applyToDefaults = function (defaults, options) {
+
+ exports.assert(defaults && typeof defaults == 'object', 'Invalid defaults value: must be an object');
+ exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
+
+ if (!options) { // If no options, return null
+ return null;
+ }
+
+ var copy = exports.clone(defaults);
+
+ if (options === true) { // If options is set to true, use defaults
+ return copy;
+ }
+
+ return exports.merge(copy, options, false, false);
+};
+
+
+// Remove duplicate items from array
+
+exports.unique = function (array, key) {
+
+ var index = {};
+ var result = [];
+
+ for (var i = 0, il = array.length; i < il; ++i) {
+ var id = (key ? array[i][key] : array[i]);
+ if (index[id] !== true) {
+
+ result.push(array[i]);
+ index[id] = true;
+ }
+ }
+
+ return result;
+};
+
+
+// Convert array into object
+
+exports.mapToObject = function (array, key) {
+
+ if (!array) {
+ return null;
+ }
+
+ var obj = {};
+ for (var i = 0, il = array.length; i < il; ++i) {
+ if (key) {
+ if (array[i][key]) {
+ obj[array[i][key]] = true;
+ }
+ }
+ else {
+ obj[array[i]] = true;
+ }
+ }
+
+ return obj;
+};
+
+
+// Find the common unique items in two arrays
+
+exports.intersect = function (array1, array2) {
+
+ if (!array1 || !array2) {
+ return [];
+ }
+
+ var common = [];
+ var hash = (array1 instanceof Array ? exports.mapToObject(array1) : array1);
+ var found = {};
+ for (var i = 0, il = array2.length; i < il; ++i) {
+ if (hash[array2[i]] && !found[array2[i]]) {
+ common.push(array2[i]);
+ found[array2[i]] = true;
+ }
+ }
+
+ return common;
+};
+
+
+// Find which keys are present
+
+exports.matchKeys = function (obj, keys) {
+
+ var matched = [];
+ for (var i = 0, il = keys.length; i < il; ++i) {
+ if (obj.hasOwnProperty(keys[i])) {
+ matched.push(keys[i]);
+ }
+ }
+ return matched;
+};
+
+
+// Flatten array
+
+exports.flatten = function (array, target) {
+
+ var result = target || [];
+
+ for (var i = 0, il = array.length; i < il; ++i) {
+ if (Array.isArray(array[i])) {
+ exports.flatten(array[i], result);
+ }
+ else {
+ result.push(array[i]);
+ }
+ }
+
+ return result;
+};
+
+
+// Remove keys
+
+exports.removeKeys = function (object, keys) {
+
+ for (var i = 0, il = keys.length; i < il; i++) {
+ delete object[keys[i]];
+ }
+};
+
+
+// Convert an object key chain string ('a.b.c') to reference (object[a][b][c])
+
+exports.reach = function (obj, chain) {
+
+ var path = chain.split('.');
+ var ref = obj;
+ path.forEach(function (level) {
+
+ if (ref) {
+ ref = ref[level];
+ }
+ });
+
+ return ref;
+};
+
+
+// Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors
+
+exports.inheritAsync = function (self, obj, keys) {
+
+ keys = keys || null;
+
+ for (var i in obj) {
+ if (obj.hasOwnProperty(i)) {
+ if (keys instanceof Array &&
+ keys.indexOf(i) < 0) {
+
+ continue;
+ }
+
+ self.prototype[i] = (function (fn) {
+
+ return function (callback) {
+
+ var result = null;
+ try {
+ result = fn();
+ }
+ catch (err) {
+ return callback(err);
+ }
+
+ return callback(null, result);
+ };
+ })(obj[i]);
+ }
+ }
+};
+
+
+exports.formatStack = function (stack) {
+
+ var trace = [];
+ stack.forEach(function (item) {
+
+ trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
+ });
+
+ return trace;
+};
+
+
+exports.formatTrace = function (trace) {
+
+ var display = [];
+ trace.forEach(function (row) {
+
+ display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
+ });
+
+ return display;
+};
+
+
+exports.callStack = function (slice) {
+
+ // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+
+ var v8 = Error.prepareStackTrace;
+ Error.prepareStackTrace = function (err, stack) {
+
+ return stack;
+ };
+
+ var capture = {};
+ Error.captureStackTrace(capture, arguments.callee);
+ var stack = capture.stack;
+
+ Error.prepareStackTrace = v8;
+
+ var trace = exports.formatStack(stack);
+
+ if (slice) {
+ return trace.slice(slice);
+ }
+
+ return trace;
+};
+
+
+exports.displayStack = function (slice) {
+
+ var trace = exports.callStack(slice === undefined ? 1 : slice + 1);
+
+ return exports.formatTrace(trace);
+};
+
+
+exports.abortThrow = false;
+
+
+exports.abort = function (message, hideStack) {
+
+ if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
+ throw new Error(message || 'Unknown error');
+ }
+
+ var stack = '';
+ if (!hideStack) {
+ stack = exports.displayStack(1).join('\n\t');
+ }
+ console.log('ABORT: ' + message + '\n\t' + stack);
+ process.exit(1);
+};
+
+
+exports.assert = function (condition, message) {
+
+ if (!condition) {
+ throw new Error(message || 'Unknown error');
+ }
+};
+
+
+exports.loadDirModules = function (path, excludeFiles, target) { // target(filename, name, capName)
+
+ var exclude = {};
+ for (var i = 0, il = excludeFiles.length; i < il; ++i) {
+ exclude[excludeFiles[i] + '.js'] = true;
+ }
+
+ Fs.readdirSync(path).forEach(function (filename) {
+
+ if (/\.js$/.test(filename) &&
+ !exclude[filename]) {
+
+ var name = filename.substr(0, filename.lastIndexOf('.'));
+ var capName = name.charAt(0).toUpperCase() + name.substr(1).toLowerCase();
+
+ if (typeof target !== 'function') {
+ target[capName] = require(path + '/' + name);
+ }
+ else {
+ target(path + '/' + name, name, capName);
+ }
+ }
+ });
+};
+
+
+exports.rename = function (obj, from, to) {
+
+ obj[to] = obj[from];
+ delete obj[from];
+};
+
+
+exports.Timer = function () {
+
+ this.reset();
+};
+
+
+exports.Timer.prototype.reset = function () {
+
+ this.ts = Date.now();
+};
+
+
+exports.Timer.prototype.elapsed = function () {
+
+ return Date.now() - this.ts;
+};
+
+
+// Load and parse package.json process root or given directory
+
+exports.loadPackage = function (dir) {
+
+ var result = {};
+ var filepath = (dir || process.env.PWD) + '/package.json';
+ if (Fs.existsSync(filepath)) {
+ try {
+ result = JSON.parse(Fs.readFileSync(filepath));
+ }
+ catch (e) { }
+ }
+
+ return result;
+};
+
+
+// Escape string for Regex construction
+
+exports.escapeRegex = function (string) {
+
+ // Escape ^$.*+-?=!:|\/()[]{},
+ return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
+};
+
+
+// Return an error as first argument of a callback
+
+exports.toss = function (condition /*, [message], callback */) {
+
+ var message = (arguments.length === 3 ? arguments[1] : '');
+ var callback = (arguments.length === 3 ? arguments[2] : arguments[1]);
+
+ var err = (message instanceof Error ? message : (message ? new Error(message) : (condition instanceof Error ? condition : new Error())));
+
+ if (condition instanceof Error ||
+ !condition) {
+
+ return callback(err);
+ }
+};
+
+
+// Base64url (RFC 4648) encode
+
+exports.base64urlEncode = function (value) {
+
+ return (new Buffer(value, 'binary')).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
+};
+
+
+// Base64url (RFC 4648) decode
+
+exports.base64urlDecode = function (encoded) {
+
+ if (encoded &&
+ !encoded.match(/^[\w\-]*$/)) {
+
+ return new Error('Invalid character');
+ }
+
+ try {
+ return (new Buffer(encoded.replace(/-/g, '+').replace(/:/g, '/'), 'base64')).toString('binary');
+ }
+ catch (err) {
+ return err;
+ }
+};
+
+
+// Escape attribute value for use in HTTP header
+
+exports.escapeHeaderAttribute = function (attribute) {
+
+ // Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
+
+ exports.assert(attribute.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/), 'Bad attribute value (' + attribute + ')');
+
+ return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"'); // Escape quotes and slash
+};
+
+
+exports.escapeHtml = function (string) {
+
+ return Escape.escapeHtml(string);
+};
+
+
+exports.escapeJavaScript = function (string) {
+
+ return Escape.escapeJavaScript(string);
+};
+
+
+/*
+var event = {
+ timestamp: now.getTime(),
+ tags: ['tag'],
+ data: { some: 'data' }
+};
+*/
+
+exports.consoleFunc = console.log;
+
+exports.printEvent = function (event) {
+
+ var pad = function (value) {
+
+ return (value < 10 ? '0' : '') + value;
+ };
+
+ var now = new Date(event.timestamp);
+ var timestring = (now.getYear() - 100).toString() +
+ pad(now.getMonth() + 1) +
+ pad(now.getDate()) +
+ '/' +
+ pad(now.getHours()) +
+ pad(now.getMinutes()) +
+ pad(now.getSeconds()) +
+ '.' +
+ now.getMilliseconds();
+
+ var data = event.data;
+ if (typeof event.data !== 'string') {
+ try {
+ data = JSON.stringify(event.data);
+ }
+ catch (e) {
+ data = 'JSON Error: ' + e.message;
+ }
+ }
+
+ var output = timestring + ', ' + event.tags[0] + ', ' + data;
+ exports.consoleFunc(output);
+};
diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/package.json b/node_modules/request/node_modules/hawk/node_modules/hoek/package.json new file mode 100755 index 000000000..813c2ce69 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/package.json @@ -0,0 +1,49 @@ +{ + "name": "hoek", + "description": "General purpose node utilities", + "version": "0.7.6", + "author": { + "name": "Eran Hammer", + "email": "eran@hueniverse.com", + "url": "http://hueniverse.com" + }, + "contributors": [ + { + "name": "Van Nguyen", + "email": "the.gol.effect@gmail.com" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/spumko/hoek" + }, + "main": "index", + "keywords": [ + "utilities" + ], + "engines": { + "node": "0.8.x" + }, + "dependencies": {}, + "devDependencies": { + "lab": "0.0.x", + "complexity-report": "0.x.x" + }, + "scripts": { + "test": "make test-cov" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/spumko/hoek/raw/master/LICENSE" + } + ], + "readme": "<a href=\"https://github.com/spumko\"><img src=\"https://raw.github.com/spumko/spumko/master/images/from.png\" align=\"right\" /></a>\n![hoek Logo](https://raw.github.com/spumko/hoek/master/images/hoek.png)\n\nGeneral purpose node utilities\n\n[![Build Status](https://secure.travis-ci.org/spumko/hoek.png)](http://travis-ci.org/spumko/hoek)\n\n# Table of Contents\n\n* [Introduction](#introduction \"Introduction\")\n* [Object](#object \"Object\")\n * [clone](#cloneobj \"clone\")\n * [merge](#mergetarget-source-isnulloverride-ismergearrays \"merge\")\n * [applyToDefaults](#applytodefaultsdefaults-options \"applyToDefaults\")\n * [unique](#uniquearray-key \"unique\")\n * [mapToObject](#maptoobjectarray-key \"mapToObject\")\n * [intersect](#intersectarray1-array2 \"intersect\")\n * [matchKeys](#matchkeysobj-keys \"matchKeys\")\n * [flatten](#flattenarray-target \"flatten\")\n * [removeKeys](#removekeysobject-keys \"removeKeys\")\n * [reach](#reachobj-chain \"reach\")\n * [inheritAsync](#inheritasyncself-obj-keys \"inheritAsync\")\n * [rename](#renameobj-from-to \"rename\")\n* [Timer](#timer \"Timer\")\n* [Binary Encoding/Decoding](#binary \"Binary Encoding/Decoding\")\n * [base64urlEncode](#binary64urlEncodevalue \"binary64urlEncode\")\n * [base64urlDecode](#binary64urlDecodevalue \"binary64urlDecode\")\n* [Escaping Characters](#escaped \"Escaping Characters\")\n * [escapeHtml](#escapeHtmlstring \"escapeHtml\")\n * [escapeHeaderAttribute](#escapeHeaderAttributeattribute \"escapeHeaderAttribute\")\n * [escapeRegex](#escapeRegexstring \"escapeRegex\")\n* [Errors](#errors \"Errors\")\n * [assert](#assertmessage \"assert\")\n * [abort](#abortmessage \"abort\")\n * [displayStack](#displayStackslice \"displayStack\")\n * [callStack](#callStackslice \"callStack\")\n * [toss](#tosscondition \"toss\")\n* [Load files](#load-files \"Load Files\")\n * [loadPackage](#loadPackagedir \"loadpackage\")\n * [loadDirModules](#loadDirModulespath-excludefiles-target \"loaddirmodules\")\n\n\n\n# Introduction\n\nThe *Hoek* general purpose node utilities library is used to aid in a variety of manners. It comes with useful methods for Ararys (clone, merge, applyToDefaults), Objects (removeKeys, copy), Asserting and more. \n\nFor example, to use Hoek to set configuration with default options:\n```javascript\nvar Hoek = require('hoek');\n\nvar default = {url : \"www.github.com\", port : \"8000\", debug : true}\n\nvar config = Hoek.applyToDefaults(default, {port : \"3000\", admin : true});\n\n// In this case, config would be { url: 'www.github.com', port: '3000', debug: true, admin: true }\n```\n\nUnder each of the sections (such as Array), there are subsections which correspond to Hoek methods. Each subsection will explain how to use the corresponding method. In each js excerpt below, the var Hoek = require('hoek') is omitted for brevity.\n\n## Object\n\nHoek provides several helpful methods for objects and arrays.\n\n### clone(obj)\n\nThis method is used to clone an object or an array. A *deep copy* is made (duplicates everything, including values that are objects). \n\n```javascript\n\nvar nestedObj = {\n w: /^something$/ig,\n x: {\n a: [1, 2, 3],\n b: 123456,\n c: new Date()\n },\n y: 'y',\n z: new Date()\n };\n\nvar copy = Hoek.clone(nestedObj);\n\ncopy.x.b = 100;\n\nconsole.log(copy.y) // results in 'y'\nconsole.log(nestedObj.x.b) // results in 123456\nconsole.log(copy.x.b) // results in 100\n```\n\n### merge(target, source, isNullOverride, isMergeArrays)\nisNullOverride, isMergeArrays default to true\n\nMerge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied\n\n\n```javascript\n\nvar target = {a: 1, b : 2}\nvar source = {a: 0, c: 5}\nvar source2 = {a: null, c: 5}\n\nvar targetArray = [1, 2, 3];\nvar sourceArray = [4, 5];\n\nvar newTarget = Hoek.merge(target, source); // results in {a: 0, b: 2, c: 5}\nnewTarget = Hoek.merge(target, source2); // results in {a: null, b: 2, c: 5}\nnewTarget = Hoek.merge(target, source2, false); // results in {a: null, b:2, c: 5}\n\nnewTarget = Hoek.merge(targetArray, sourceArray) // results in [1, 2, 3, 4, 5]\nnewTarget = Hoek.merge(targetArray, sourceArray, true, false) // results in [4, 5]\n\n\n\n\n```\n\n### applyToDefaults(defaults, options)\n\nApply options to a copy of the defaults\n\n```javascript\n\nvar defaults = {host: \"localhost\", port: 8000};\nvar options = {port: 8080};\n\nvar config = Hoek.applyToDefaults(defaults, options); // results in {host: \"localhost\", port: 8080};\n\n\n```\n\n### unique(array, key)\n\nRemove duplicate items from Array\n\n```javascript\n\nvar array = [1, 2, 2, 3, 3, 4, 5, 6];\n\nvar newArray = Hoek.unique(array); // results in [1,2,3,4,5,6];\n\narray = [{id: 1}, {id: 1}, {id: 2}];\n\nnewArray = Hoek.unique(array, \"id\") // results in [{id: 1}, {id: 2}]\n\n```\n\n### mapToObject(array, key)\n\nConvert an Array into an Object\n\n```javascript\n\nvar array = [1,2,3];\nvar newObject = Hoek.mapToObject(array); // results in [{\"1\": true}, {\"2\": true}, {\"3\": true}]\n\narray = [{id: 1}, {id: 2}];\nnewObject = Hoek.mapToObject(array, \"id\") // results in [{\"id\": 1}, {\"id\": 2}]\n\n```\n### intersect(array1, array2)\n\nFind the common unique items in two arrays\n\n```javascript\n\nvar array1 = [1, 2, 3];\nvar array2 = [1, 4, 5];\n\nvar newArray = Hoek.intersect(array1, array2) // results in [1]\n\n```\n\n### matchKeys(obj, keys) \n\nFind which keys are present\n\n```javascript\n\nvar obj = {a: 1, b: 2, c: 3};\nvar keys = [\"a\", \"e\"];\n\nHoek.matchKeys(obj, keys) // returns [\"a\"]\n\n```\n\n### flatten(array, target)\n\nFlatten an array\n\n```javascript\n\nvar array = [1, 2, 3];\nvar target = [4, 5]; \n\nvar flattenedArray = Hoek.flatten(array, target) // results in [4, 5, 1, 2, 3];\n\n```\n\n### removeKeys(object, keys)\n\nRemove keys\n\n```javascript\n\nvar object = {a: 1, b: 2, c: 3, d: 4};\n\nvar keys = [\"a\", \"b\"];\n\nHoek.removeKeys(object, keys) // object is now {c: 3, d: 4}\n\n```\n\n### reach(obj, chain)\n\nConverts an object key chain string to reference\n\n```javascript\n\nvar chain = 'a.b.c';\nvar obj = {a : {b : { c : 1}}};\n\nHoek.reach(obj, chain) // returns 1\n\n```\n\n### inheritAsync(self, obj, keys) \n\nInherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors\n\n```javascript\n\nvar targetFunc = function () { };\n\nvar proto = {\n a: function () {\n return 'a!';\n },\n b: function () {\n return 'b!';\n },\n c: function () {\n throw new Error('c!');\n }\n };\n\nvar keys = ['a', 'c'];\n\nHoek.inheritAsync(targetFunc, proto, ['a', 'c']);\n\nvar target = new targetFunc();\n\ntarget.a(function(err, result){console.log(result)} // returns 'a!' \n\ntarget.c(function(err, result){console.log(result)} // returns undefined\n\ntarget.b(function(err, result){console.log(result)} // gives error: Object [object Object] has no method 'b'\n\n```\n\n### rename(obj, from, to)\n\nRename a key of an object\n\n```javascript\n\nvar obj = {a : 1, b : 2};\n\nHoek.rename(obj, \"a\", \"c\"); // obj is now {c : 1, b : 2}\n\n```\n\n\n# Timer\n\nA Timer object. Initializing a new timer object sets the ts to the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.\n\n```javascript\n\n\nexample : \n\n\nvar timerObj = new Hoek.Timer();\nconsole.log(\"Time is now: \" + timerObj.ts)\nconsole.log(\"Elapsed time from initialization: \" + timerObj.elapsed() + 'milliseconds')\n\n```\n\n# Binary Encoding/Decoding\n\n### base64urlEncode(value)\n\nEncodes value in Base64 or URL encoding\n\n### base64urlDecode(value)\n\nDecodes data in Base64 or URL encoding.\n# Escaping Characters\n\nHoek provides convenient methods for escaping html characters. The escaped characters are as followed:\n\n```javascript\n\ninternals.htmlEscaped = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n '`': '`'\n};\n\n```\n\n### escapeHtml(string)\n\n```javascript\n\nvar string = '<html> hey </html>';\nvar escapedString = Hoek.escapeHtml(string); // returns <html> hey </html>\n\n```\n\n### escapeHeaderAttribute(attribute)\n\nEscape attribute value for use in HTTP header\n\n```javascript\n\nvar a = Hoek.escapeHeaderAttribute('I said \"go w\\\\o me\"'); //returns I said \\\"go w\\\\o me\\\"\n\n\n```\n\n\n### escapeRegex(string)\n\nEscape string for Regex construction\n\n```javascript\n\nvar a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\\\/`\"(>)[<]d{}s,'); // returns 4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`\"\\(>\\)\\[<\\]d\\{\\}s\\,\n\n\n\n```\n\n# Errors\n\n### assert(message)\n\n```javascript\n\nvar a = 1, b =2;\n\nHoek.assert(a === b, 'a should equal b'); // ABORT: a should equal b\n\n```\n\n### abort(message)\n\nFirst checks if process.env.NODE_ENV === 'test', and if so, throws error message. Otherwise,\ndisplays most recent stack and then exits process.\n\n\n\n### displayStack(slice)\n\nDisplays the trace stack\n\n```javascript\n\nvar stack = Hoek.displayStack();\nconsole.log(stack) // returns something like:\n\n[ 'null (/Users/user/Desktop/hoek/test.js:4:18)',\n 'Module._compile (module.js:449:26)',\n 'Module._extensions..js (module.js:467:10)',\n 'Module.load (module.js:356:32)',\n 'Module._load (module.js:312:12)',\n 'Module.runMain (module.js:492:10)',\n 'startup.processNextTick.process._tickCallback (node.js:244:9)' ]\n\n```\n\n### callStack(slice)\n\nReturns a trace stack array.\n\n```javascript\n\nvar stack = Hoek.callStack();\nconsole.log(stack) // returns something like:\n\n[ [ '/Users/user/Desktop/hoek/test.js', 4, 18, null, false ],\n [ 'module.js', 449, 26, 'Module._compile', false ],\n [ 'module.js', 467, 10, 'Module._extensions..js', false ],\n [ 'module.js', 356, 32, 'Module.load', false ],\n [ 'module.js', 312, 12, 'Module._load', false ],\n [ 'module.js', 492, 10, 'Module.runMain', false ],\n [ 'node.js',\n 244,\n 9,\n 'startup.processNextTick.process._tickCallback',\n false ] ]\n\n\n```\n\n### toss(condition)\n\ntoss(condition /*, [message], callback */)\n\nReturn an error as first argument of a callback\n\n\n# Load Files\n\n### loadPackage(dir)\n\nLoad and parse package.json process root or given directory\n\n```javascript\n\nvar pack = Hoek.loadPackage(); // pack.name === 'hoek'\n\n```\n\n### loadDirModules(path, excludeFiles, target) \n\nLoads modules from a given path; option to exclude files (array).\n\n\n\n\n", + "readmeFilename": "README.md", + "_id": "hoek@0.7.6", + "dist": { + "shasum": "30c553c4bbfd8f78015fb48a8d643b966490cb32" + }, + "_from": "hoek@0.7.x", + "_resolved": "https://registry.npmjs.org/hoek/-/hoek-0.7.6.tgz" +} diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/test/escaper.js b/node_modules/request/node_modules/hawk/node_modules/hoek/test/escaper.js new file mode 100644 index 000000000..4dddd77dc --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/test/escaper.js @@ -0,0 +1,86 @@ +// Load modules
+
+var Lab = require('lab');
+var Hoek = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hoek', function () {
+
+ describe('#escapeJavaScript', function () {
+
+ it('encodes / characters', function (done) {
+
+ var encoded = Hoek.escapeJavaScript('<script>alert(1)</script>');
+ expect(encoded).to.equal('\\x3cscript\\x3ealert\\x281\\x29\\x3c\\x2fscript\\x3e');
+ done();
+ });
+
+ it('encodes \' characters', function (done) {
+
+ var encoded = Hoek.escapeJavaScript('something(\'param\')');
+ expect(encoded).to.equal('something\\x28\\x27param\\x27\\x29');
+ done();
+ });
+
+ it('encodes large unicode characters with the correct padding', function (done) {
+
+ var encoded = Hoek.escapeJavaScript(String.fromCharCode(500) + String.fromCharCode(1000));
+ expect(encoded).to.equal('\\u0500\\u1000');
+ done();
+ });
+
+ it('doesn\'t throw an exception when passed null', function (done) {
+
+ var encoded = Hoek.escapeJavaScript(null);
+ expect(encoded).to.equal('');
+ done();
+ });
+ });
+
+ describe('#escapeHtml', function () {
+
+ it('encodes / characters', function (done) {
+
+ var encoded = Hoek.escapeHtml('<script>alert(1)</script>');
+ expect(encoded).to.equal('<script>alert(1)</script>');
+ done();
+ });
+
+ it('encodes < and > as named characters', function (done) {
+
+ var encoded = Hoek.escapeHtml('<script><>');
+ expect(encoded).to.equal('<script><>');
+ done();
+ });
+
+ it('encodes large unicode characters', function (done) {
+
+ var encoded = Hoek.escapeHtml(String.fromCharCode(500) + String.fromCharCode(1000));
+ expect(encoded).to.equal('ǴϨ');
+ done();
+ });
+
+ it('doesn\'t throw an exception when passed null', function (done) {
+
+ var encoded = Hoek.escapeHtml(null);
+ expect(encoded).to.equal('');
+ done();
+ });
+ });
+});
+
+
diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/test/index.js b/node_modules/request/node_modules/hawk/node_modules/hoek/test/index.js new file mode 100755 index 000000000..5edafe326 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/test/index.js @@ -0,0 +1,983 @@ +// Load modules
+
+var Lab = require('lab');
+var Hoek = require('../lib');
+
+
+// Declare internals
+
+var internals = {};
+
+
+// Test shortcuts
+
+var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+
+
+describe('Hoek', function () {
+
+ var nestedObj = {
+ v: [7,8,9],
+ w: /^something$/igm,
+ x: {
+ a: [1, 2, 3],
+ b: 123456,
+ c: new Date(),
+ d: /hi/igm,
+ e: /hello/
+ },
+ y: 'y',
+ z: new Date()
+ };
+
+ var dupsArray = [nestedObj, { z: 'z' }, nestedObj];
+ var reducedDupsArray = [nestedObj, { z: 'z' }];
+
+ describe('#clone', function () {
+
+ it('should clone a nested object', function (done) {
+
+ var a = nestedObj;
+ var b = Hoek.clone(a);
+
+ expect(a).to.deep.equal(b);
+ expect(a.z.getTime()).to.equal(b.z.getTime());
+ done();
+ });
+
+ it('should clone a null object', function (done) {
+
+ var b = Hoek.clone(null);
+
+ expect(b).to.equal(null);
+ done();
+ });
+
+ it('should not convert undefined properties to null', function (done) {
+
+ var obj = { something: undefined };
+ var b = Hoek.clone(obj);
+
+ expect(typeof b.something).to.equal('undefined');
+ done();
+ });
+
+ it('should not throw on circular reference', function (done) {
+
+ var a = {};
+ a.x = a;
+
+ var test = (function () {
+
+ var b = Hoek.clone(a);
+ });
+
+ expect(test).to.not.throw();
+ done();
+ });
+
+ it('should properly clone circular reference', function (done) {
+
+ var x = {
+ 'z': new Date()
+ };
+ x.y = x;
+
+ var b = Hoek.clone(x);
+ expect(Object.keys(b.y)).to.deep.equal(Object.keys(x))
+ expect(b.z).to.not.equal(x.z);
+ expect(b.y).to.not.equal(x.y);
+ expect(b.y.z).to.not.equal(x.y.z);
+ expect(b.y).to.equal(b);
+ expect(b.y.y.y.y).to.equal(b);
+ done();
+ });
+
+ it('should properly clone deeply nested object', function (done) {
+
+ var a = {
+ x: {
+ y: {
+ a: [1, 2, 3],
+ b: 123456,
+ c: new Date(),
+ d: /hi/igm,
+ e: /hello/
+ },
+ }
+ };
+
+ var b = Hoek.clone(a);
+
+ expect(a).to.deep.equal(b);
+ expect(a.x.y.c.getTime()).to.equal(b.x.y.c.getTime());
+ done();
+ });
+
+ it('should properly clone arrays', function (done) {
+
+ var a = [1,2,3];
+
+ var b = Hoek.clone(a);
+
+ expect(a).to.deep.equal(b);
+ done();
+ });
+
+ it('should perform actual copy for shallow keys (no pass by reference)', function (done) {
+
+ var x = Hoek.clone(nestedObj);
+ var y = Hoek.clone(nestedObj);
+
+ // Date
+ expect(x.z).to.not.equal(nestedObj.z);
+ expect(x.z).to.not.equal(y.z);
+
+ // Regex
+ expect(x.w).to.not.equal(nestedObj.w);
+ expect(x.w).to.not.equal(y.w);
+
+ // Array
+ expect(x.v).to.not.equal(nestedObj.v);
+ expect(x.v).to.not.equal(y.v);
+
+ // Immutable(s)
+ x.y = 5;
+ expect(x.y).to.not.equal(nestedObj.y);
+ expect(x.y).to.not.equal(y.y);
+
+ done();
+ });
+
+ it('should perform actual copy for deep keys (no pass by reference)', function (done) {
+
+ var x = Hoek.clone(nestedObj);
+ var y = Hoek.clone(nestedObj);
+
+ expect(x.x.c).to.not.equal(nestedObj.x.c);
+ expect(x.x.c).to.not.equal(y.x.c);
+
+ expect(x.x.c.getTime()).to.equal(nestedObj.x.c.getTime());
+ expect(x.x.c.getTime()).to.equal(y.x.c.getTime());
+ done();
+ });
+
+ it('copies functions with properties', function (done) {
+
+ var a = {
+ x: function () { return 1; },
+ y: {}
+ };
+ a.x.z = 'string in function';
+ a.x.v = function () { return 2; };
+ a.y.u = a.x;
+
+ var b = Hoek.clone(a);
+ expect(b.x()).to.equal(1);
+ expect(b.x.v()).to.equal(2);
+ expect(b.y.u).to.equal(b.x);
+ expect(b.x.z).to.equal('string in function');
+ done();
+ });
+ });
+
+ describe('#merge', function () {
+
+ it('does not throw if source is null', function (done) {
+
+ var a = {};
+ var b = null;
+ var c = null;
+
+ expect(function () {
+
+ c = Hoek.merge(a, b);
+ }).to.not.throw();
+
+ expect(c).to.equal(a);
+ done();
+ });
+
+ it('does not throw if source is undefined', function (done) {
+
+ var a = {};
+ var b = undefined;
+ var c = null;
+
+ expect(function () {
+
+ c = Hoek.merge(a, b);
+ }).to.not.throw();
+
+ expect(c).to.equal(a);
+ done();
+ });
+
+ it('throws if source is not an object', function (done) {
+
+ expect(function () {
+
+ var a = {};
+ var b = 0;
+
+ Hoek.merge(a, b);
+ }).to.throw('Invalid source value: must be null, undefined, or an object');
+ done();
+ });
+
+ it('throws if target is not an object', function (done) {
+
+ expect(function () {
+
+ var a = 0;
+ var b = {};
+
+ Hoek.merge(a, b);
+ }).to.throw('Invalid target value: must be an object');
+ done();
+ });
+
+ it('throws if target is not an array and source is', function (done) {
+
+ expect(function () {
+
+ var a = {};
+ var b = [1, 2];
+
+ Hoek.merge(a, b);
+ }).to.throw('Cannot merge array onto an object');
+ done();
+ });
+
+ it('returns the same object when merging arrays', function (done) {
+
+ var a = [];
+ var b = [1, 2];
+
+ expect(Hoek.merge(a, b)).to.equal(a);
+ done();
+ });
+
+ it('should combine an empty object with a non-empty object', function (done) {
+
+ var a = {};
+ var b = nestedObj;
+
+ var c = Hoek.merge(a, b);
+ expect(a).to.deep.equal(b);
+ expect(c).to.deep.equal(b);
+ done();
+ });
+
+ it('should override values in target', function (done) {
+
+ var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
+ var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
+
+ var c = Hoek.merge(a, b);
+ expect(c.x).to.equal(null);
+ expect(c.y).to.equal(2);
+ expect(c.z).to.equal(4);
+ expect(c.v).to.equal(0);
+ expect(c.m).to.equal('123');
+ expect(c.t).to.deep.equal({ u: 6 });
+ done();
+ });
+
+ it('should override values in target (flip)', function (done) {
+
+ var a = { x: 1, y: 2, z: 3, v: 5, t: 'test', m: 'abc' };
+ var b = { x: null, z: 4, v: 0, t: { u: 6 }, m: '123' };
+
+ var d = Hoek.merge(b, a);
+ expect(d.x).to.equal(1);
+ expect(d.y).to.equal(2);
+ expect(d.z).to.equal(3);
+ expect(d.v).to.equal(5);
+ expect(d.m).to.equal('abc');
+ expect(d.t).to.deep.equal('test');
+ done();
+ });
+ });
+
+ describe('#applyToDefaults', function () {
+
+ var defaults = {
+ a: 1,
+ b: 2,
+ c: {
+ d: 3,
+ e: [5, 6]
+ },
+ f: 6,
+ g: 'test'
+ };
+
+ it('should return null if options is false', function (done) {
+
+ var result = Hoek.applyToDefaults(defaults, false);
+ expect(result).to.equal(null);
+ done();
+ });
+
+ it('should return a copy of defaults if options is true', function (done) {
+
+ var result = Hoek.applyToDefaults(defaults, true);
+ expect(result).to.deep.equal(result);
+ done();
+ });
+
+ it('should apply object to defaults', function (done) {
+
+ var obj = {
+ a: null,
+ c: {
+ e: [4]
+ },
+ f: 0,
+ g: {
+ h: 5
+ }
+ };
+
+ var result = Hoek.applyToDefaults(defaults, obj);
+ expect(result.c.e).to.deep.equal([4]);
+ expect(result.a).to.equal(1);
+ expect(result.b).to.equal(2);
+ expect(result.f).to.equal(0);
+ expect(result.g).to.deep.equal({ h: 5 });
+ done();
+ });
+ });
+
+ describe('#unique', function () {
+
+ it('should ensure uniqueness within array of objects based on subkey', function (done) {
+
+ var a = Hoek.unique(dupsArray, 'x');
+ expect(a).to.deep.equal(reducedDupsArray);
+ done();
+ });
+
+ it('removes duplicated without key', function (done) {
+
+ expect(Hoek.unique([1, 2, 3, 4, 2, 1, 5])).to.deep.equal([1, 2, 3, 4, 5]);
+ done();
+ });
+ });
+
+ describe('#mapToObject', function () {
+
+ it('should return null on null array', function (done) {
+
+ var a = Hoek.mapToObject(null);
+ expect(a).to.equal(null);
+ done();
+ });
+
+ it('should convert basic array to existential object', function (done) {
+
+ var keys = [1, 2, 3, 4];
+ var a = Hoek.mapToObject(keys);
+ for (var i in keys) {
+ expect(a[keys[i]]).to.equal(true);
+ }
+ done();
+ });
+
+ it('should convert array of objects to existential object', function (done) {
+
+ var keys = [{ x: 1 }, { x: 2 }, { x: 3 }];
+ var subkey = 'x';
+ var a = Hoek.mapToObject(keys, subkey);
+ for (var i in keys) {
+ expect(a[keys[i][subkey]]).to.equal(true);
+ }
+ done();
+ });
+ });
+
+ describe('#intersect', function () {
+
+ it('should return the common objects of two arrays', function (done) {
+
+ var array1 = [1, 2, 3, 4, 4, 5, 5];
+ var array2 = [5, 4, 5, 6, 7];
+ var common = Hoek.intersect(array1, array2);
+ expect(common.length).to.equal(2);
+ done();
+ });
+
+ it('should return an empty array if either input is null', function (done) {
+
+ expect(Hoek.intersect([1], null).length).to.equal(0);
+ expect(Hoek.intersect(null, [1]).length).to.equal(0);
+ done();
+ });
+
+ it('should return the common objects of object and array', function (done) {
+
+ var array1 = [1, 2, 3, 4, 4, 5, 5];
+ var array2 = [5, 4, 5, 6, 7];
+ var common = Hoek.intersect(Hoek.mapToObject(array1), array2);
+ expect(common.length).to.equal(2);
+ done();
+ });
+ });
+
+ describe('#matchKeys', function () {
+
+ it('should match the existing object keys', function (done) {
+
+ var obj = {
+ a: 1,
+ b: 2,
+ c: 3,
+ d: null
+ };
+
+ expect(Hoek.matchKeys(obj, ['b', 'c', 'd', 'e'])).to.deep.equal(['b', 'c', 'd']);
+ done();
+ });
+ });
+
+ describe('#flatten', function () {
+
+ it('should return a flat array', function (done) {
+
+ var result = Hoek.flatten([1, 2, [3, 4, [5, 6], [7], 8], [9], [10, [11, 12]], 13]);
+ expect(result.length).to.equal(13);
+ expect(result).to.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
+ done();
+ });
+ });
+
+ describe('#removeKeys', function () {
+
+ var objWithHiddenKeys = {
+ location: {
+ name: 'San Bruno'
+ },
+ company: {
+ name: '@WalmartLabs'
+ }
+ };
+
+ it('should delete params with definition\'s hide set to true', function (done) {
+
+ var a = Hoek.removeKeys(objWithHiddenKeys, ['location']);
+ expect(objWithHiddenKeys.location).to.not.exist;
+ expect(objWithHiddenKeys.company).to.exist;
+ done();
+ });
+ });
+
+ describe('#reach', function () {
+
+ var obj = {
+ a: {
+ b: {
+ c: {
+ d: 1,
+ e: 2
+ },
+ f: 'hello'
+ },
+ g: {
+ h: 3
+ }
+ },
+ i: function () { }
+ };
+
+ it('returns a valid member', function (done) {
+
+ expect(Hoek.reach(obj, 'a.b.c.d')).to.equal(1);
+ done();
+ });
+
+ it('returns null on null object', function (done) {
+
+ expect(Hoek.reach(null, 'a.b.c.d')).to.not.exist;
+ done();
+ });
+
+ it('returns null on missing member', function (done) {
+
+ expect(Hoek.reach(obj, 'a.b.c.d.x')).to.not.exist;
+ done();
+ });
+
+ it('returns null on invalid member', function (done) {
+
+ expect(Hoek.reach(obj, 'a.b.c.d-.x')).to.not.exist;
+ done();
+ });
+
+ it('returns function member', function (done) {
+
+ expect(typeof Hoek.reach(obj, 'i')).to.equal('function');
+ done();
+ });
+ });
+
+ describe('#inheritAsync', function () {
+
+ it('should inherit selected methods and wrap in async call', function (done) {
+
+ var proto = {
+ a: function () {
+ return 'a!';
+ },
+ b: function () {
+ return 'b!';
+ },
+ c: function () {
+ throw new Error('c!');
+ }
+ };
+
+ var targetFunc = function () { };
+ targetFunc.prototype.c = function () {
+
+ return 'oops';
+ };
+
+ Hoek.inheritAsync(targetFunc, proto, ['a', 'c']);
+ var target = new targetFunc();
+
+ expect(typeof target.a).to.equal('function');
+ expect(typeof target.c).to.equal('function');
+ expect(target.b).to.not.exist;
+
+ target.a(function (err, result) {
+
+ expect(err).to.not.exist;
+ expect(result).to.equal('a!');
+
+ target.c(function (err, result) {
+
+ expect(result).to.not.exist;
+ expect(err.message).to.equal('c!');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('#callStack', function () {
+
+ it('should return the full call stack', function (done) {
+
+ var stack = Hoek.callStack();
+ expect(stack[0][0]).to.contain('index.js');
+ expect(stack[0][2]).to.equal(30);
+ done();
+ });
+ });
+
+ describe('#displayStack ', function () {
+
+ it('should return the full call stack for display', function (done) {
+
+ var stack = Hoek.displayStack();
+ expect(stack[0]).to.contain('test/index.js:');
+ done();
+ });
+
+ it('should include constructor functions correctly', function (done) {
+
+ var Something = function (next) {
+
+ next();
+ };
+
+ var something = new Something(function () {
+
+ var stack = Hoek.displayStack();
+ expect(stack[1]).to.contain('new Something');
+ done();
+ });
+ });
+ });
+
+ describe('#abort', function () {
+
+ it('should exit process when not in test mode', function (done) {
+
+ var env = process.env.NODE_ENV;
+ var write = process.stdout.write;
+ var exit = process.exit;
+
+ process.env.NODE_ENV = 'nottatest';
+ process.stdout.write = function () { };
+ process.exit = function (state) {
+
+ process.exit = exit;
+ process.env.NODE_ENV = env;
+ process.stdout.write = write;
+
+ expect(state).to.equal(1);
+ done();
+ };
+
+ Hoek.abort('Boom');
+ });
+
+ it('should throw when not in test mode and abortThrow is true', function (done) {
+
+ var env = process.env.NODE_ENV;
+ process.env.NODE_ENV = 'nottatest';
+ Hoek.abortThrow = true;
+
+ var fn = function () {
+
+ Hoek.abort('my error message');
+ };
+
+ expect(fn).to.throw('my error message');
+ Hoek.abortThrow = false;
+ process.env.NODE_ENV = env;
+
+ done();
+ });
+
+
+ it('should respect hideStack argument', function (done) {
+
+ var env = process.env.NODE_ENV;
+ var write = process.stdout.write;
+ var exit = process.exit;
+ var output = '';
+
+ process.exit = function () { };
+ process.env.NODE_ENV = '';
+ process.stdout.write = function (message) {
+
+ output = message;
+ };
+
+ Hoek.abort('my error message', true);
+
+ process.env.NODE_ENV = env;
+ process.stdout.write = write;
+ process.exit = exit;
+
+ expect(output).to.equal('ABORT: my error message\n\t\n');
+
+ done();
+ });
+
+ it('should default to showing stack', function (done) {
+
+ var env = process.env.NODE_ENV;
+ var write = process.stdout.write;
+ var exit = process.exit;
+ var output = '';
+
+ process.exit = function () { };
+ process.env.NODE_ENV = '';
+ process.stdout.write = function (message) {
+
+ output = message;
+ };
+
+ Hoek.abort('my error message');
+
+ process.env.NODE_ENV = env;
+ process.stdout.write = write;
+ process.exit = exit;
+
+ expect(output).to.contain('index.js');
+
+ done();
+ });
+ });
+
+ describe('#assert', function () {
+
+ it('should throw an Error when using assert in a test', function (done) {
+
+ var fn = function () {
+
+ Hoek.assert(false, 'my error message');
+ };
+
+ expect(fn).to.throw('my error message');
+ done();
+ });
+ });
+
+ describe('#loadDirModules', function () {
+
+ it('should load modules from directory', function (done) {
+
+ var target = {};
+ Hoek.loadDirModules(__dirname + '/modules', ['test2'], target);
+ expect(target.Test1.x).to.equal(1);
+ expect(target.Test2).to.not.exist;
+ expect(target.Test3.z).to.equal(3);
+ done();
+ });
+
+ it('should list modules from directory into function', function (done) {
+
+ var target = {};
+ Hoek.loadDirModules(__dirname + '/modules', ['test2'], function (path, name, capName) {
+
+ target[name] = capName;
+ });
+
+ expect(target.test1).to.equal('Test1');
+ expect(target.test2).to.not.exist;
+ expect(target.test3).to.equal('Test3');
+ done();
+ });
+ });
+
+ describe('#rename', function () {
+
+ it('should rename object key', function (done) {
+
+ var a = { b: 'c' };
+ Hoek.rename(a, 'b', 'x');
+ expect(a.b).to.not.exist;
+ expect(a.x).to.equal('c');
+ done();
+ });
+ });
+
+ describe('Timer', function () {
+
+ it('should return time elapsed', function (done) {
+
+ var timer = new Hoek.Timer();
+ setTimeout(function () {
+
+ expect(timer.elapsed()).to.be.above(9);
+ done();
+ }, 12);
+ });
+ });
+
+ describe('#loadPackage', function () {
+
+ it('should', function (done) {
+
+ var pack = Hoek.loadPackage();
+ expect(pack.name).to.equal('hoek');
+ done();
+ });
+ });
+
+ describe('#escapeRegex', function () {
+
+ it('should escape all special regular expression characters', function (done) {
+
+ var a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');
+ expect(a).to.equal('4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`"\\(>\\)\\[<\\]d\\{\\}s\\,');
+ done();
+ });
+ });
+
+ describe('#toss', function () {
+
+ it('should call callback with new error', function (done) {
+
+ var callback = function (err) {
+
+ expect(err).to.exist;
+ expect(err.message).to.equal('bug');
+ done();
+ };
+
+ Hoek.toss(true, 'feature', callback);
+ Hoek.toss(false, 'bug', callback);
+ });
+
+ it('should call callback with new error and no message', function (done) {
+
+ Hoek.toss(false, function (err) {
+
+ expect(err).to.exist;
+ expect(err.message).to.equal('');
+ done();
+ });
+ });
+
+ it('should call callback with error condition', function (done) {
+
+ Hoek.toss(new Error('boom'), function (err) {
+
+ expect(err).to.exist;
+ expect(err.message).to.equal('boom');
+ done();
+ });
+ });
+
+ it('should call callback with new error using message with error condition', function (done) {
+
+ Hoek.toss(new Error('ka'), 'boom', function (err) {
+
+ expect(err).to.exist;
+ expect(err.message).to.equal('boom');
+ done();
+ });
+ });
+
+ it('should call callback with new error using passed error with error condition', function (done) {
+
+ Hoek.toss(new Error('ka'), new Error('boom'), function (err) {
+
+ expect(err).to.exist;
+ expect(err.message).to.equal('boom');
+ done();
+ });
+ });
+ });
+
+ describe('Base64Url', function () {
+
+ var base64str = 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w';
+ var str = unescape('%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29*+%2C-./0123456789%3A%3B%3C%3D%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF');
+
+ describe('#base64urlEncode', function () {
+
+ it('should base64 URL-safe a string', function (done) {
+
+ expect(Hoek.base64urlEncode(str)).to.equal(base64str);
+ done();
+ });
+ });
+
+ describe('#base64urlDecode', function () {
+
+ it('should un-base64 URL-safe a string', function (done) {
+
+ expect(Hoek.base64urlDecode(base64str)).to.equal(str);
+ done();
+ });
+
+ it('should return error on undefined input', function (done) {
+
+ expect(Hoek.base64urlDecode().message).to.exist;
+ done();
+ });
+
+ it('should return error on invalid input', function (done) {
+
+ expect(Hoek.base64urlDecode('*').message).to.exist;
+ done();
+ });
+ });
+ });
+
+ describe('#escapeHeaderAttribute', function () {
+
+ it('should not alter ascii values', function (done) {
+
+ var a = Hoek.escapeHeaderAttribute('My Value');
+ expect(a).to.equal('My Value');
+ done();
+ });
+
+ it('should escape all special HTTP header attribute characters', function (done) {
+
+ var a = Hoek.escapeHeaderAttribute('I said go!!!#"' + String.fromCharCode(92));
+ expect(a).to.equal('I said go!!!#\\"\\\\');
+ done();
+ });
+
+ it('should throw on large unicode characters', function (done) {
+
+ var fn = function () {
+
+ Hoek.escapeHeaderAttribute('this is a test' + String.fromCharCode(500) + String.fromCharCode(300));
+ };
+
+ expect(fn).to.throw(Error);
+ done();
+ });
+
+ it('should throw on CRLF to prevent response splitting', function (done) {
+
+ var fn = function () {
+
+ Hoek.escapeHeaderAttribute('this is a test\r\n');
+ };
+
+ expect(fn).to.throw(Error);
+ done();
+ });
+ });
+
+ describe('#escapeHtml', function () {
+
+ it('should escape all special HTML characters', function (done) {
+
+ var a = Hoek.escapeHtml('&<>"\'`');
+ expect(a).to.equal('&<>"'`');
+ done();
+ });
+
+ it('should return empty string on falsy input', function (done) {
+
+ var a = Hoek.escapeHtml('');
+ expect(a).to.equal('');
+ done();
+ });
+
+ it('should return unchanged string on no reserved input', function (done) {
+
+ var a = Hoek.escapeHtml('abc');
+ expect(a).to.equal('abc');
+ done();
+ });
+ });
+
+ describe('#printEvent', function () {
+
+ it('outputs event as string', function (done) {
+
+ var event = {
+ timestamp: (new Date(2013, 1, 1, 6, 30, 45, 123)).getTime(),
+ tags: ['a', 'b', 'c'],
+ data: { some: 'data' }
+ };
+
+ Hoek.consoleFunc = function (string) {
+
+ Hoek.consoleFunc = console.log;
+ expect(string).to.equal('130201/063045.123, a, {"some":"data"}');
+ done();
+ };
+
+ Hoek.printEvent(event);
+ });
+
+ it('outputs JSON error', function (done) {
+
+ var event = {
+ timestamp: (new Date(2013, 1, 1, 6, 30, 45, 123)).getTime(),
+ tags: ['a', 'b', 'c'],
+ data: { some: 'data' }
+ };
+
+ event.data.a = event.data;
+
+ Hoek.consoleFunc = function (string) {
+
+ Hoek.consoleFunc = console.log;
+ expect(string).to.equal('130201/063045.123, a, JSON Error: Converting circular structure to JSON');
+ done();
+ };
+
+ Hoek.printEvent(event);
+ });
+ });
+});
+
diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test1.js b/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test1.js new file mode 100755 index 000000000..fa4e06abe --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test1.js @@ -0,0 +1 @@ +exports.x = 1; diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test2.js b/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test2.js new file mode 100755 index 000000000..88e9166e8 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test2.js @@ -0,0 +1 @@ +exports.y = 2; diff --git a/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test3.js b/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test3.js new file mode 100755 index 000000000..670e724a6 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/hoek/test/modules/test3.js @@ -0,0 +1 @@ +exports.z = 3; diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/.npmignore b/node_modules/request/node_modules/hawk/node_modules/sntp/.npmignore new file mode 100644 index 000000000..77ba16cb0 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/.npmignore @@ -0,0 +1,18 @@ +.idea +*.iml +npm-debug.log +dump.rdb +node_modules +results.tap +results.xml +npm-shrinkwrap.json +config.json +.DS_Store +*/.DS_Store +*/*/.DS_Store +._* +*/._* +*/*/._* +coverage.* +lib-cov + diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/.travis.yml b/node_modules/request/node_modules/hawk/node_modules/sntp/.travis.yml new file mode 100755 index 000000000..d8523c933 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/.travis.yml @@ -0,0 +1,5 @@ +language: node_js + +node_js: + - 0.8 + diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/LICENSE b/node_modules/request/node_modules/hawk/node_modules/sntp/LICENSE new file mode 100755 index 000000000..e699a7bdb --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2012-2013, Eran Hammer. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Eran Hammer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ERAN HAMMER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/Makefile b/node_modules/request/node_modules/hawk/node_modules/sntp/Makefile new file mode 100755 index 000000000..97ba3af43 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/Makefile @@ -0,0 +1,11 @@ +test:
+ @./node_modules/.bin/lab
+test-cov:
+ @./node_modules/.bin/lab -r threshold -t 100
+test-cov-html:
+ @./node_modules/.bin/lab -r html -o coverage.html
+complexity:
+ @./node_modules/.bin/cr -o complexity.md -f markdown lib
+
+.PHONY: test test-cov test-cov-html complexity
+
diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/README.md b/node_modules/request/node_modules/hawk/node_modules/sntp/README.md new file mode 100755 index 000000000..fab80e990 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/README.md @@ -0,0 +1,70 @@ +# sntp + +An SNTP v4 client (RFC4330) for node. Simpy connects to the NTP or SNTP server requested and returns the server time +along with the roundtrip duration and clock offset. To adjust the local time to the NTP time, add the returned `t` offset +to the local time. + +Current version: **0.1.1** + +[![Build Status](https://secure.travis-ci.org/hueniverse/sntp.png)](http://travis-ci.org/hueniverse/sntp) + +# Usage + +```javascript +var Sntp = require('sntp'); + +// All options are optional + +var options = { + host: 'nist1-sj.ustiming.org', // Defaults to pool.ntp.org + port: 123, // Defaults to 123 (NTP) + resolveReference: true, // Default to false (not resolving) + timeout: 1000 // Defaults to zero (no timeout) +}; + +// Request server time + +Sntp.time(options, function (err, time) { + + if (err) { + console.log('Failed: ' + err.message); + process.exit(1); + } + + console.log('Local clock is off by: ' + time.t + ' milliseconds'); + process.exit(0); +}); +``` + +If an application needs to maintain continuous time synchronization, the module provides a stateful method for +querying the current offset only when the last one is too old (defaults to daily). + +```javascript +// Request offset once + +Sntp.offset(function (err, offset) { + + console.log(offset); // New (served fresh) + + // Request offset again + + Sntp.offset(function (err, offset) { + + console.log(offset); // Identical (served from cache) + }); +}); +``` + +To set a background offset refresh, start the interval and use the provided now() method. If for any reason the +client fails to obtain an up-to-date offset, the current system clock is used. + +```javascript +var before = Sntp.now(); // System time without offset + +Sntp.start(function () { + + var now = Sntp.now(); // With offset + Sntp.stop(); +}); +``` + diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/examples/offset.js b/node_modules/request/node_modules/hawk/node_modules/sntp/examples/offset.js new file mode 100755 index 000000000..0303f6dcf --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/examples/offset.js @@ -0,0 +1,16 @@ +var Sntp = require('../lib'); + +// Request offset once + +Sntp.offset(function (err, offset) { + + console.log(offset); // New (served fresh) + + // Request offset again + + Sntp.offset(function (err, offset) { + + console.log(offset); // Identical (served from cache) + }); +}); + diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/examples/time.js b/node_modules/request/node_modules/hawk/node_modules/sntp/examples/time.js new file mode 100755 index 000000000..bd70d0e6a --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/examples/time.js @@ -0,0 +1,25 @@ +var Sntp = require('../lib'); + +// All options are optional + +var options = { + host: 'nist1-sj.ustiming.org', // Defaults to pool.ntp.org + port: 123, // Defaults to 123 (NTP) + resolveReference: true, // Default to false (not resolving) + timeout: 1000 // Defaults to zero (no timeout) +}; + +// Request server time + +Sntp.time(options, function (err, time) { + + if (err) { + console.log('Failed: ' + err.message); + process.exit(1); + } + + console.log(time); + console.log('Local clock is off by: ' + time.t + ' milliseconds'); + process.exit(0); +}); + diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/index.js b/node_modules/request/node_modules/hawk/node_modules/sntp/index.js new file mode 100755 index 000000000..4cc88b358 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/index.js @@ -0,0 +1 @@ +module.exports = require('./lib');
\ No newline at end of file diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js b/node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js new file mode 100755 index 000000000..2b4ab4ac6 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/lib/index.js @@ -0,0 +1,398 @@ +// Load modules + +var Dgram = require('dgram'); +var Dns = require('dns'); +var Hoek = require('hoek'); + + +// Declare internals + +var internals = {}; + + +exports.time = function (options, callback) { + + if (arguments.length !== 2) { + callback = arguments[0]; + options = {}; + } + + var settings = Hoek.clone(options); + settings.host = settings.host || 'pool.ntp.org'; + settings.port = settings.port || 123; + settings.resolveReference = settings.resolveReference || false; + + // Declare variables used by callback + + var timeoutId = 0; + var sent = 0; + + // Ensure callback is only called once + + var isFinished = false; + var finish = function (err, result) { + + if (timeoutId) { + clearTimeout(timeoutId); + timeoutId = 0; + } + + if (!isFinished) { + isFinished = true; + socket.close(); + return callback(err, result); + } + }; + + // Create UDP socket + + var socket = Dgram.createSocket('udp4'); + + socket.on('error', function (err) { + + return finish(err); + }); + + // Listen to incoming messages + + socket.on('message', function (buffer, rinfo) { + + var received = Date.now(); + + var message = new internals.NtpMessage(buffer); + if (!message.isValid) { + return finish(new Error('Invalid server response'), message); + } + + if (message.originateTimestamp !== sent) { + return finish(new Error('Wrong originate timestamp'), message); + } + + // Timestamp Name ID When Generated + // ------------------------------------------------------------ + // Originate Timestamp T1 time request sent by client + // Receive Timestamp T2 time request received by server + // Transmit Timestamp T3 time reply sent by server + // Destination Timestamp T4 time reply received by client + // + // The roundtrip delay d and system clock offset t are defined as: + // + // d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2 + + var T1 = message.originateTimestamp; + var T2 = message.receiveTimestamp; + var T3 = message.transmitTimestamp; + var T4 = received; + + message.d = (T4 - T1) - (T3 - T2); + message.t = ((T2 - T1) + (T3 - T4)) / 2; + message.receivedLocally = received; + + if (!settings.resolveReference || + message.stratum !== 'secondary') { + + return finish(null, message); + } + + // Resolve reference IP address + + Dns.reverse(message.referenceId, function (err, domains) { + + if (!err) { + message.referenceHost = domains[0]; + } + + return finish(null, message); + }); + }); + + // Set timeout + + if (settings.timeout) { + timeoutId = setTimeout(function () { + + timeoutId = 0; + return finish(new Error('Timeout')); + }, settings.timeout); + } + + // Construct NTP message + + var message = new Buffer(48); + for (var i = 0; i < 48; i++) { // Zero message + message[i] = 0; + } + + message[0] = (0 << 6) + (4 << 3) + (3 << 0) // Set version number to 4 and Mode to 3 (client) + sent = Date.now(); + internals.fromMsecs(sent, message, 40); // Set transmit timestamp (returns as originate) + + // Send NTP request + + socket.send(message, 0, message.length, settings.port, settings.host, function (err, bytes) { + + if (err || + bytes !== 48) { + + return finish(err || new Error('Could not send entire message')); + } + }); +}; + + +internals.NtpMessage = function (buffer) { + + this.isValid = false; + + // Validate + + if (buffer.length !== 48) { + return; + } + + // Leap indicator + + var li = (buffer[0] >> 6); + switch (li) { + case 0: this.leapIndicator = 'no-warning'; break; + case 1: this.leapIndicator = 'last-minute-61'; break; + case 2: this.leapIndicator = 'last-minute-59'; break; + case 3: this.leapIndicator = 'alarm'; break; + } + + // Version + + var vn = ((buffer[0] & 0x38) >> 3); + this.version = vn; + + // Mode + + var mode = (buffer[0] & 0x7); + switch (mode) { + case 1: this.mode = 'symmetric-active'; break; + case 2: this.mode = 'symmetric-passive'; break; + case 3: this.mode = 'client'; break; + case 4: this.mode = 'server'; break; + case 5: this.mode = 'broadcast'; break; + case 0: + case 6: + case 7: this.mode = 'reserved'; break; + } + + // Stratum + + var stratum = buffer[1]; + if (stratum === 0) { + this.stratum = 'death'; + } + else if (stratum === 1) { + this.stratum = 'primary'; + } + else if (stratum <= 15) { + this.stratum = 'secondary'; + } + else { + this.stratum = 'reserved'; + } + + // Poll interval (msec) + + this.pollInterval = Math.round(Math.pow(2, buffer[2])) * 1000; + + // Precision (msecs) + + this.precision = Math.pow(2, buffer[3]) * 1000; + + // Root delay (msecs) + + var rootDelay = 256 * (256 * (256 * buffer[4] + buffer[5]) + buffer[6]) + buffer[7]; + this.rootDelay = 1000 * (rootDelay / 0x10000); + + // Root dispersion (msecs) + + this.rootDispersion = ((buffer[8] << 8) + buffer[9] + ((buffer[10] << 8) + buffer[11]) / Math.pow(2, 16)) * 1000; + + // Reference identifier + + this.referenceId = ''; + switch (this.stratum) { + case 'death': + case 'primary': + this.referenceId = String.fromCharCode(buffer[12]) + String.fromCharCode(buffer[13]) + String.fromCharCode(buffer[14]) + String.fromCharCode(buffer[15]); + break; + case 'secondary': + this.referenceId = '' + buffer[12] + '.' + buffer[13] + '.' + buffer[14] + '.' + buffer[15]; + break; + } + + // Reference timestamp + + this.referenceTimestamp = internals.toMsecs(buffer, 16); + + // Originate timestamp + + this.originateTimestamp = internals.toMsecs(buffer, 24); + + // Receive timestamp + + this.receiveTimestamp = internals.toMsecs(buffer, 32); + + // Transmit timestamp + + this.transmitTimestamp = internals.toMsecs(buffer, 40); + + // Validate + + if (this.version === 4 && + this.stratum !== 'reserved' && + this.mode === 'server' && + this.originateTimestamp && + this.receiveTimestamp && + this.transmitTimestamp) { + + this.isValid = true; + } + + return this; +}; + + +internals.toMsecs = function (buffer, offset) { + + var seconds = 0; + var fraction = 0; + + for (var i = 0; i < 4; ++i) { + seconds = (seconds * 256) + buffer[offset + i]; + } + + for (i = 4; i < 8; ++i) { + fraction = (fraction * 256) + buffer[offset + i]; + } + + return ((seconds - 2208988800 + (fraction / Math.pow(2, 32))) * 1000); +}; + + +internals.fromMsecs = function (ts, buffer, offset) { + + var seconds = Math.floor(ts / 1000) + 2208988800; + var fraction = Math.round((ts % 1000) / 1000 * Math.pow(2, 32)); + + buffer[offset + 0] = (seconds & 0xFF000000) >> 24; + buffer[offset + 1] = (seconds & 0x00FF0000) >> 16; + buffer[offset + 2] = (seconds & 0x0000FF00) >> 8; + buffer[offset + 3] = (seconds & 0x000000FF); + + buffer[offset + 4] = (fraction & 0xFF000000) >> 24; + buffer[offset + 5] = (fraction & 0x00FF0000) >> 16; + buffer[offset + 6] = (fraction & 0x0000FF00) >> 8; + buffer[offset + 7] = (fraction & 0x000000FF); +}; + + +// Offset singleton + +internals.last = { + offset: 0, + expires: 0, + host: '', + port: 0 +}; + + +exports.offset = function (options, callback) { + + if (arguments.length !== 2) { + callback = arguments[0]; + options = {}; + } + + var now = Date.now(); + var clockSyncRefresh = options.clockSyncRefresh || 24 * 60 * 60 * 1000; // Daily + + if (internals.last.offset && + internals.last.host === options.host && + internals.last.port === options.port && + now < internals.last.expires) { + + return callback(null, internals.last.offset); + } + + exports.time(options, function (err, time) { + + if (err) { + return callback(err, 0); + } + + internals.last = { + offset: Math.round(time.t), + expires: now + clockSyncRefresh, + host: options.host, + port: options.port + }; + + return callback(null, internals.last.offset); + }); +}; + + +// Now singleton + +internals.now = { + intervalId: 0 +}; + + +exports.start = function (options, callback) { + + if (arguments.length !== 2) { + callback = arguments[0]; + options = {}; + } + + if (internals.now.intervalId) { + return callback(); + } + + exports.offset(options, function (err, offset) { + + internals.now.intervalId = setInterval(function () { + + exports.offset(options, function () { }); + }, options.clockSyncRefresh || 24 * 60 * 60 * 1000); // Daily + + return callback(); + }); +}; + + +exports.stop = function () { + + if (!internals.now.intervalId) { + return; + } + + clearInterval(internals.now.intervalId); + internals.now.intervalId = 0; +}; + + +exports.isLive = function () { + + return !!internals.now.intervalId; +}; + + +exports.now = function () { + + var now = Date.now(); + if (!exports.isLive() || + now >= internals.last.expires) { + + return now; + } + + return now + internals.last.offset; +}; + diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/package.json b/node_modules/request/node_modules/hawk/node_modules/sntp/package.json new file mode 100755 index 000000000..3a6879e76 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/package.json @@ -0,0 +1,48 @@ +{ + "name": "sntp", + "description": "SNTP Client", + "version": "0.1.4", + "author": { + "name": "Eran Hammer", + "email": "eran@hueniverse.com", + "url": "http://hueniverse.com" + }, + "contributors": [], + "repository": { + "type": "git", + "url": "git://github.com/hueniverse/sntp" + }, + "main": "index", + "keywords": [ + "sntp", + "ntp", + "time" + ], + "engines": { + "node": "0.8.x" + }, + "dependencies": { + "hoek": "0.7.x" + }, + "devDependencies": { + "lab": "0.0.x", + "complexity-report": "0.x.x" + }, + "scripts": { + "test": "make test-cov" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/hueniverse/sntp/raw/master/LICENSE" + } + ], + "readme": "# sntp\n\nAn SNTP v4 client (RFC4330) for node. Simpy connects to the NTP or SNTP server requested and returns the server time\nalong with the roundtrip duration and clock offset. To adjust the local time to the NTP time, add the returned `t` offset\nto the local time.\n\nCurrent version: **0.1.1**\n\n[![Build Status](https://secure.travis-ci.org/hueniverse/sntp.png)](http://travis-ci.org/hueniverse/sntp)\n\n# Usage\n\n```javascript\nvar Sntp = require('sntp');\n\n// All options are optional\n\nvar options = {\n host: 'nist1-sj.ustiming.org', // Defaults to pool.ntp.org\n port: 123, // Defaults to 123 (NTP)\n resolveReference: true, // Default to false (not resolving)\n timeout: 1000 // Defaults to zero (no timeout)\n};\n\n// Request server time\n\nSntp.time(options, function (err, time) {\n\n if (err) {\n console.log('Failed: ' + err.message);\n process.exit(1);\n }\n\n console.log('Local clock is off by: ' + time.t + ' milliseconds');\n process.exit(0);\n});\n```\n\nIf an application needs to maintain continuous time synchronization, the module provides a stateful method for\nquerying the current offset only when the last one is too old (defaults to daily).\n\n```javascript\n// Request offset once\n\nSntp.offset(function (err, offset) {\n\n console.log(offset); // New (served fresh)\n\n // Request offset again\n\n Sntp.offset(function (err, offset) {\n\n console.log(offset); // Identical (served from cache)\n });\n});\n```\n\nTo set a background offset refresh, start the interval and use the provided now() method. If for any reason the\nclient fails to obtain an up-to-date offset, the current system clock is used.\n\n```javascript\nvar before = Sntp.now(); // System time without offset\n\nSntp.start(function () {\n\n var now = Sntp.now(); // With offset\n Sntp.stop();\n});\n```\n\n", + "readmeFilename": "README.md", + "_id": "sntp@0.1.4", + "dist": { + "shasum": "e37864ac9cb8b2926b338396cb9dd8a3df49231a" + }, + "_from": "sntp@0.1.x", + "_resolved": "https://registry.npmjs.org/sntp/-/sntp-0.1.4.tgz" +} diff --git a/node_modules/request/node_modules/hawk/node_modules/sntp/test/index.js b/node_modules/request/node_modules/hawk/node_modules/sntp/test/index.js new file mode 100755 index 000000000..7332e32c1 --- /dev/null +++ b/node_modules/request/node_modules/hawk/node_modules/sntp/test/index.js @@ -0,0 +1,339 @@ +// Load modules + +var Dgram = require('dgram'); +var Lab = require('lab');
+var Sntp = require('../lib'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+ + +describe('SNTP', function () { + + describe('#time', function () { + + it('returns consistent result over multiple tries', function (done) { + + Sntp.time(function (err, time) { + + expect(err).to.not.exist; + expect(time).to.exist; + var t1 = time.t; + + Sntp.time(function (err, time) { + + expect(err).to.not.exist; + expect(time).to.exist; + var t2 = time.t; + expect(Math.abs(t1 - t2)).is.below(200); + done(); + }); + }); + }); + + it('resolves reference IP', function (done) { + + Sntp.time({ host: 'ntp.exnet.com', resolveReference: true }, function (err, time) { + + expect(err).to.not.exist; + expect(time).to.exist; + expect(time.referenceHost).to.exist; + done(); + }); + }); + + it('times out on no response', function (done) { + + Sntp.time({ port: 124, timeout: 100 }, function (err, time) { + + expect(err).to.exist; + expect(time).to.not.exist; + expect(err.message).to.equal('Timeout'); + done(); + }); + }); + + it('times out on no response', function (done) { + + Sntp.time({ host: 'error', timeout: 10000 }, function (err, time) { + + expect(err).to.exist; + expect(time).to.not.exist; + expect(err.message).to.equal('getaddrinfo ENOTFOUND'); + done(); + }); + }); + + it('fails on bad response buffer size', function (done) { + + var server = Dgram.createSocket('udp4'); + server.on('message', function (message, remote) { + var message = new Buffer(10); + server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) { + + server.close(); + }); + }); + + server.bind(49123); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(err).to.exist; + expect(err.message).to.equal('Invalid server response'); + done(); + }); + }); + + var messup = function (bytes) { + + var server = Dgram.createSocket('udp4'); + server.on('message', function (message, remote) { + + var message = new Buffer([ + 0x24, 0x01, 0x00, 0xe3, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x41, 0x43, 0x54, 0x53, + 0xd4, 0xa8, 0x2d, 0xc7, + 0x1c, 0x5d, 0x49, 0x1b, + 0xd4, 0xa8, 0x2d, 0xe6, + 0x67, 0xef, 0x9d, 0xb2, + 0xd4, 0xa8, 0x2d, 0xe6, + 0x71, 0xed, 0xb5, 0xfb, + 0xd4, 0xa8, 0x2d, 0xe6, + 0x71, 0xee, 0x6c, 0xc5 + ]); + + for (var i = 0, il = bytes.length; i < il; ++i) { + message[bytes[i][0]] = bytes[i][1]; + } + + server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) { + + server.close(); + }); + }); + + server.bind(49123); + }; + + it('fails on bad version', function (done) { + + messup([[0, (0 << 6) + (3 << 3) + (4 << 0)]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(err).to.exist; + expect(time.version).to.equal(3); + expect(err.message).to.equal('Invalid server response'); + done(); + }); + }); + + it('fails on bad originate timestamp and alarm li', function (done) { + + messup([[0, (3 << 6) + (4 << 3) + (4 << 0)]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(err).to.exist; + expect(err.message).to.equal('Wrong originate timestamp'); + expect(time.leapIndicator).to.equal('alarm'); + done(); + }); + }); + + it('returns time with death stratum and last61 li', function (done) { + + messup([[0, (1 << 6) + (4 << 3) + (4 << 0)], [1, 0]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(time.stratum).to.equal('death'); + expect(time.leapIndicator).to.equal('last-minute-61'); + done(); + }); + }); + + it('returns time with reserved stratum and last59 li', function (done) { + + messup([[0, (2 << 6) + (4 << 3) + (4 << 0)], [1, 0x1f]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(time.stratum).to.equal('reserved'); + expect(time.leapIndicator).to.equal('last-minute-59'); + done(); + }); + }); + + it('fails on bad mode (symmetric-active)', function (done) { + + messup([[0, (0 << 6) + (4 << 3) + (1 << 0)]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(err).to.exist; + expect(time.mode).to.equal('symmetric-active'); + done(); + }); + }); + + it('fails on bad mode (symmetric-passive)', function (done) { + + messup([[0, (0 << 6) + (4 << 3) + (2 << 0)]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(err).to.exist; + expect(time.mode).to.equal('symmetric-passive'); + done(); + }); + }); + + it('fails on bad mode (client)', function (done) { + + messup([[0, (0 << 6) + (4 << 3) + (3 << 0)]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(err).to.exist; + expect(time.mode).to.equal('client'); + done(); + }); + }); + + it('fails on bad mode (broadcast)', function (done) { + + messup([[0, (0 << 6) + (4 << 3) + (5 << 0)]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(err).to.exist; + expect(time.mode).to.equal('broadcast'); + done(); + }); + }); + + it('fails on bad mode (reserved)', function (done) { + + messup([[0, (0 << 6) + (4 << 3) + (6 << 0)]]); + + Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) { + + expect(err).to.exist; + expect(time.mode).to.equal('reserved'); + done(); + }); + }); + }); + + describe('#offset', function () { + + it('gets the current offset', function (done) { + + Sntp.offset(function (err, offset) { + + expect(err).to.not.exist; + expect(offset).to.not.equal(0); + done(); + }); + }); + + it('gets the current offset from cache', function (done) { + + Sntp.offset(function (err, offset) { + + expect(err).to.not.exist; + expect(offset).to.not.equal(0); + var offset1 = offset; + Sntp.offset({}, function (err, offset) { + + expect(err).to.not.exist; + expect(offset).to.equal(offset1); + done(); + }); + }); + }); + + it('fails getting the current offset on invalid server', function (done) { + + Sntp.offset({ host: 'error' }, function (err, offset) { + + expect(err).to.exist; + expect(offset).to.equal(0); + done(); + }); + }); + }); + + describe('#now', function () { + + it('starts auto-sync, gets now, then stops', function (done) { + + Sntp.stop(); + + var before = Sntp.now(); + expect(before).to.equal(Date.now()); + + Sntp.start(function () { + + var now = Sntp.now(); + expect(now).to.not.equal(Date.now()); + Sntp.stop(); + + done(); + }); + }); + + it('starts twice', function (done) { + + Sntp.start(function () { + + Sntp.start(function () { + + var now = Sntp.now(); + expect(now).to.not.equal(Date.now()); + Sntp.stop(); + + done(); + }); + }); + }); + + it('starts auto-sync, gets now, waits, gets again after timeout', function (done) { + + Sntp.stop(); + + var before = Sntp.now(); + expect(before).to.equal(Date.now()); + + Sntp.start({ clockSyncRefresh: 100 }, function () { + + var now = Sntp.now(); + expect(now).to.not.equal(Date.now()); + expect(now).to.equal(Sntp.now()); + + setTimeout(function () { + + expect(Sntp.now()).to.not.equal(now); + Sntp.stop(); + done(); + }, 110); + }); + }); + }); +}); + diff --git a/node_modules/request/node_modules/hawk/package.json b/node_modules/request/node_modules/hawk/package.json new file mode 100755 index 000000000..85cf8602a --- /dev/null +++ b/node_modules/request/node_modules/hawk/package.json @@ -0,0 +1,52 @@ +{ + "name": "hawk", + "description": "HTTP Hawk Authentication Scheme", + "version": "0.10.2", + "author": { + "name": "Eran Hammer", + "email": "eran@hueniverse.com", + "url": "http://hueniverse.com" + }, + "contributors": [], + "repository": { + "type": "git", + "url": "git://github.com/hueniverse/hawk" + }, + "main": "index", + "keywords": [ + "http", + "authentication", + "scheme", + "hawk" + ], + "engines": { + "node": "0.8.x" + }, + "dependencies": { + "hoek": "0.7.x", + "boom": "0.3.x", + "cryptiles": "0.1.x", + "sntp": "0.1.x" + }, + "devDependencies": { + "lab": "0.0.x", + "complexity-report": "0.x.x" + }, + "scripts": { + "test": "make test-cov" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/hueniverse/hawk/raw/master/LICENSE" + } + ], + "readme": "![hawk Logo](https://raw.github.com/hueniverse/hawk/master/images/hawk.png)\r\n\r\n<img align=\"right\" src=\"https://raw.github.com/hueniverse/hawk/master/images/logo.png\" /> **Hawk** is an HTTP authentication scheme using a message authentication code (MAC) algorithm to provide partial\r\nHTTP request cryptographic verification. For more complex use cases such as access delegation, see [Oz](https://github.com/hueniverse/oz).\r\n\r\nCurrent version: **0.10.1**\r\n\r\n[![Build Status](https://secure.travis-ci.org/hueniverse/hawk.png)](http://travis-ci.org/hueniverse/hawk)\r\n\r\n# Table of Content\r\n\r\n- [**Introduction**](#introduction)\r\n - [Replay Protection](#replay-protection)\r\n - [Usage Example](#usage-example)\r\n - [Protocol Example](#protocol-example)\r\n - [Payload Validation](#payload-validation)\r\n - [Response Payload Validation](#response-payload-validation)\r\n<p></p>\r\n- [**Single URI Authorization**](#single-uri-authorization)\r\n - [Usage Example](#bewit-usage-example)\r\n<p></p>\r\n- [**Security Considerations**](#security-considerations)\r\n - [MAC Keys Transmission](#mac-keys-transmission)\r\n - [Confidentiality of Requests](#confidentiality-of-requests)\r\n - [Spoofing by Counterfeit Servers](#spoofing-by-counterfeit-servers)\r\n - [Plaintext Storage of Credentials](#plaintext-storage-of-credentials)\r\n - [Entropy of Keys](#entropy-of-keys)\r\n - [Coverage Limitations](#coverage-limitations)\r\n - [Future Time Manipulation](#future-time-manipulation)\r\n - [Client Clock Poisoning](#client-clock-poisoning)\r\n - [Bewit Limitations](#bewit-limitations)\r\n<p></p>\r\n- [**Frequently Asked Questions**](#frequently-asked-questions)\r\n<p></p>\r\n- [**Acknowledgements**](#acknowledgements)\r\n\r\n# Introduction\r\n\r\n**Hawk** is an HTTP authentication scheme providing mechanisms for making authenticated HTTP requests with\r\npartial cryptographic verification of the request and response, covering the HTTP method, request URI, host,\r\nand optionally the request payload.\r\n\r\nSimilar to the HTTP [Digest access authentication schemes](http://www.ietf.org/rfc/rfc2617.txt), **Hawk** uses a set of\r\nclient credentials which include an identifier (e.g. username) and key (e.g. password). Likewise, just as with the Digest scheme,\r\nthe key is never included in authenticated requests. Instead, it is used to calculate a request MAC value which is\r\nincluded in its place.\r\n\r\nHowever, **Hawk** has several differences from Digest. In particular, while both use a nonce to limit the possibility of\r\nreplay attacks, in **Hawk** the client generates the nonce and uses it in combination with a timestamp, leading to less\r\n\"chattiness\" (interaction with the server).\r\n\r\nAlso unlike Digest, this scheme is not intended to protect the key itself (the password in Digest) because\r\nthe client and server must both have access to the key material in the clear.\r\n\r\nThe primary design goals of this scheme are to:\r\n* simplify and improve HTTP authentication for services that are unwilling or unable to deploy TLS for all resources,\r\n* secure credentials against leakage (e.g., when the client uses some form of dynamic configuration to determine where\r\n to send an authenticated request), and\r\n* avoid the exposure of credentials sent to a malicious server over an unauthenticated secure channel due to client\r\n failure to validate the server's identity as part of its TLS handshake.\r\n\r\nIn addition, **Hawk** supports a method for granting third-parties temporary access to individual resources using\r\na query parameter called _bewit_ (in falconry, a leather strap used to attach a tracking device to the leg of a hawk).\r\n\r\nThe **Hawk** scheme requires the establishment of a shared symmetric key between the client and the server,\r\nwhich is beyond the scope of this module. Typically, the shared credentials are established via an initial\r\nTLS-protected phase or derived from some other shared confidential information available to both the client\r\nand the server.\r\n\r\n\r\n## Replay Protection\r\n\r\nWithout replay protection, an attacker can use a compromised (but otherwise valid and authenticated) request more \r\nthan once, gaining access to a protected resource. To mitigate this, clients include both a nonce and a timestamp when \r\nmaking requests. This gives the server enough information to prevent replay attacks.\r\n\r\nThe nonce is generated by the client, and is a string unique across all requests with the same timestamp and\r\nkey identifier combination. \r\n\r\nThe timestamp enables the server to restrict the validity period of the credentials where requests occuring afterwards\r\nare rejected. It also removes the need for the server to retain an unbounded number of nonce values for future checks.\r\nBy default, **Hawk** uses a time window of 1 minute to allow for time skew between the client and server (which in\r\npractice translates to a maximum of 2 minutes as the skew can be positive or negative).\r\n\r\nUsing a timestamp requires the client's clock to be in sync with the server's clock. **Hawk** requires both the client\r\nclock and the server clock to use NTP to ensure synchronization. However, given the limitations of some client types\r\n(e.g. browsers) to deploy NTP, the server provides the client with its current time in response to a bad timestamp.\r\n\r\nThere is no expectation that the client will adjust its system clock to match the server (in fact, this would be a\r\npotential attack vector). Instead, the client only uses the server's time to calculate an offset used only\r\nfor communications with that particular server. The protocol rewards clients with synchronized clocks by reducing\r\nthe number of round trips required to authenticate the first request.\r\n\r\n\r\n## Usage Example\r\n\r\nServer code:\r\n\r\n```javascript\r\nvar Http = require('http');\r\nvar Hawk = require('hawk');\r\n\r\n\r\n// Credentials lookup function\r\n\r\nvar credentialsFunc = function (id, callback) {\r\n\r\n var credentials = {\r\n key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',\r\n algorithm: 'sha256',\r\n user: 'Steve'\r\n };\r\n\r\n return callback(null, credentials);\r\n};\r\n\r\n// Create HTTP server\r\n\r\nvar handler = function (req, res) {\r\n\r\n // Authenticate incoming request\r\n\r\n Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {\r\n\r\n // Prepare response\r\n\r\n var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');\r\n var headers = { 'Content-Type': 'text/plain' };\r\n\r\n // Generate Server-Authorization response header\r\n\r\n var header = Hawk.server.header(artifacts, { payload: payload, contentType: headers['Content-Type'] });\r\n headers['Server-Authorization'] = header;\r\n\r\n // Send the response back\r\n\r\n res.writeHead(!err ? 200 : 401, headers);\r\n res.end(payload);\r\n });\r\n};\r\n\r\n// Start server\r\n\r\nHttp.createServer(handler).listen(8000, 'example.com');\r\n```\r\n\r\nClient code:\r\n\r\n```javascript\r\nvar Request = require('request');\r\nvar Hawk = require('hawk');\r\n\r\n\r\n// Client credentials\r\n\r\nvar credentials = {\r\n id: 'dh37fgj492je',\r\n key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',\r\n algorithm: 'sha256'\r\n}\r\n\r\n// Request options\r\n\r\nvar requestOptions = {\r\n uri: 'http://example.com:8000/resource/1?b=1&a=2',\r\n method: 'GET',\r\n headers: {}\r\n};\r\n\r\n// Generate Authorization request header\r\n\r\nvar header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' });\r\nrequestOptions.headers.Authorization = header.field;\r\n\r\n// Send authenticated request\r\n\r\nRequest(requestOptions, function (error, response, body) {\r\n\r\n // Authenticate the server's response\r\n\r\n var isValid = Hawk.client.authenticate(response, header.artifacts, { payload: body });\r\n\r\n // Output results\r\n\r\n console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));\r\n});\r\n```\r\n\r\n**Hawk** utilized the [**SNTP**](https://github.com/hueniverse/sntp) module for time sync management. By default, the local\r\nmachine time is used. To automatically retrieve and synchronice the clock within the application, use the SNTP 'start()' method.\r\n\r\n```javascript\r\nHawk.sntp.start();\r\n```\r\n\r\n\r\n## Protocol Example\r\n\r\nThe client attempts to access a protected resource without authentication, sending the following HTTP request to\r\nthe resource server:\r\n\r\n```\r\nGET /resource/1?b=1&a=2 HTTP/1.1\r\nHost: example.com:8000\r\n```\r\n\r\nThe resource server returns an authentication challenge.\r\n\r\n```\r\nHTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Hawk\r\n```\r\n\r\nThe client has previously obtained a set of **Hawk** credentials for accessing resources on the \"http://example.com/\"\r\nserver. The **Hawk** credentials issued to the client include the following attributes:\r\n\r\n* Key identifier: dh37fgj492je\r\n* Key: werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn\r\n* Algorithm: sha256\r\n\r\nThe client generates the authentication header by calculating a timestamp (e.g. the number of seconds since January 1,\r\n1970 00:00:00 GMT), generating a nonce, and constructing the normalized request string (each value followed by a newline\r\ncharacter):\r\n\r\n```\r\nhawk.1.header\r\n1353832234\r\nj4h3g2\r\nGET\r\n/resource?a=1&b=2\r\nexample.com\r\n8000\r\n\r\nsome-app-ext-data\r\n\r\n```\r\n\r\nThe request MAC is calculated using HMAC with the specified hash algorithm \"sha256\" and the key over the normalized request string.\r\nThe result is base64-encoded to produce the request MAC:\r\n\r\n```\r\n6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\r\n```\r\n\r\nThe client includes the **Hawk** key identifier, timestamp, nonce, application specific data, and request MAC with the request using\r\nthe HTTP `Authorization` request header field:\r\n\r\n```\r\nGET /resource/1?b=1&a=2 HTTP/1.1\r\nHost: example.com:8000\r\nAuthorization: Hawk id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", ext=\"some-app-ext-data\", mac=\"6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE=\"\r\n```\r\n\r\nThe server validates the request by calculating the request MAC again based on the request received and verifies the validity\r\nand scope of the **Hawk** credentials. If valid, the server responds with the requested resource.\r\n\r\n\r\n### Payload Validation\r\n\r\n**Hawk** provides optional payload validation. When generating the authentication header, the client calculates a payload hash\r\nusing the specified hash algorithm. The hash is calculated over the concatenated value of (each followed by a newline character):\r\n* `hawk.1.payload`\r\n* the content-type in lowercase, without any parameters (e.g. `application/json`)\r\n* the request payload prior to any content encoding (the exact representation requirements should be specified by the server for payloads other than simple single-part ascii to ensure interoperability)\r\n\r\nFor example:\r\n\r\n* Payload: `Thank you for flying Hawk`\r\n* Content Type: `text/plain`\r\n* Hash (sha256): `Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=`\r\n\r\nResults in the following input to the payload hash function (newline terminated values):\r\n\r\n```\r\nhawk.1.payload\r\ntext/plain\r\nThank you for flying Hawk\r\n\r\n```\r\n\r\nWhich produces the following hash value:\r\n\r\n```\r\nYi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\r\n```\r\n\r\nThe client constructs the normalized request string (newline terminated values):\r\n\r\n```\r\nhawk.1.header\r\n1353832234\r\nj4h3g2\r\nPOST\r\n/resource?a=1&b=2\r\nexample.com\r\n8000\r\nYi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\r\nsome-app-ext-data\r\n\r\n```\r\n\r\nThen calculates the request MAC and includes the **Hawk** key identifier, timestamp, nonce, payload hash, application specific data,\r\nand request MAC, with the request using the HTTP `Authorization` request header field:\r\n\r\n```\r\nPOST /resource/1 HTTP/1.1\r\nHost: example.com:8000\r\nAuthorization: Hawk id=\"dh37fgj492je\", ts=\"1353832234\", nonce=\"j4h3g2\", hash=\"Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\", ext=\"some-app-ext-data\", mac=\"aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw=\"\r\n```\r\n\r\nIt is up to the server if and when it validates the payload for any given request, based solely on it's security policy\r\nand the nature of the data included.\r\n\r\nIf the payload is available at the time of authentication, the server uses the hash value provided by the client to construct\r\nthe normalized string and validates the MAC. If the MAC is valid, the server calculates the payload hash and compares the value\r\nwith the provided payload hash in the header. In many cases, checking the MAC first is faster than calculating the payload hash.\r\n\r\nHowever, if the payload is not available at authentication time (e.g. too large to fit in memory, streamed elsewhere, or processed\r\nat a different stage in the application), the server may choose to defer payload validation for later by retaining the hash value\r\nprovided by the client after validating the MAC.\r\n\r\nIt is important to note that MAC validation does not mean the hash value provided by the client is valid, only that the value\r\nincluded in the header was not modified. Without calculating the payload hash on the server and comparing it to the value provided\r\nby the client, the payload may be modified by an attacker.\r\n\r\n\r\n## Response Payload Validation\r\n\r\n**Hawk** provides partial response payload validation. The server includes the `Server-Authorization` response header which enables the\r\nclient to authenticate the response and ensure it is talking to the right server. **Hawk** defines the HTTP `Server-Authorization` header\r\nas a response header using the exact same syntax as the `Authorization` request header field.\r\n\r\nThe header is contructed using the same process as the client's request header. The server uses the same credentials and other\r\nartifacts provided by the client to constructs the normalized request string. The `ext` and `hash` values are replaced with\r\nnew values based on the server response. The rest as identical to those used by the client.\r\n\r\nThe result MAC digest is included with the optional `hash` and `ext` values:\r\n\r\n```\r\nServer-Authorization: Hawk mac=\"XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=\", hash=\"f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=\", ext=\"response-specific\"\r\n```\r\n\r\n\r\n# Single URI Authorization\r\n\r\nThere are cases in which limited and short-term access to a protected resource is granted to a third party which does not\r\nhave access to the shared credentials. For example, displaying a protected image on a web page accessed by anyone. **Hawk**\r\nprovides limited support for such URIs in the form of a _bewit_ - a URI query parameter appended to the request URI which contains\r\nthe necessary credentials to authenticate the request.\r\n\r\nBecause of the significant security risks involved in issuing such access, bewit usage is purposely limited only to GET requests\r\nand for a finite period of time. Both the client and server can issue bewit credentials, however, the server should not use the same\r\ncredentials as the client to maintain clear traceability as to who issued which credentials.\r\n\r\nIn order to simplify implementation, bewit credentials do not support single-use policy and can be replayed multiple times within\r\nthe granted access timeframe. \r\n\r\n\r\n## Bewit Usage Example\r\n\r\nServer code:\r\n\r\n```javascript\r\nvar Http = require('http');\r\nvar Hawk = require('hawk');\r\n\r\n\r\n// Credentials lookup function\r\n\r\nvar credentialsFunc = function (id, callback) {\r\n\r\n var credentials = {\r\n key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',\r\n algorithm: 'sha256'\r\n };\r\n\r\n return callback(null, credentials);\r\n};\r\n\r\n// Create HTTP server\r\n\r\nvar handler = function (req, res) {\r\n\r\n Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {\r\n\r\n res.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' });\r\n res.end(!err ? 'Access granted' : 'Shoosh!');\r\n });\r\n};\r\n\r\nHttp.createServer(handler).listen(8000, 'example.com');\r\n```\r\n\r\nBewit code generation:\r\n\r\n```javascript\r\nvar Request = require('request');\r\nvar Hawk = require('hawk');\r\n\r\n\r\n// Client credentials\r\n\r\nvar credentials = {\r\n id: 'dh37fgj492je',\r\n key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',\r\n algorithm: 'sha256'\r\n}\r\n\r\n// Generate bewit\r\n\r\nvar duration = 60 * 5; // 5 Minutes\r\nvar bewit = Hawk.uri.getBewit('http://example.com:8080/resource/1?b=1&a=2', { credentials: credentials, ttlSec: duration, ext: 'some-app-data' });\r\nvar uri = 'http://example.com:8000/resource/1?b=1&a=2' + '&bewit=' + bewit;\r\n```\r\n\r\n\r\n# Security Considerations\r\n\r\nThe greatest sources of security risks are usually found not in **Hawk** but in the policies and procedures surrounding its use.\r\nImplementers are strongly encouraged to assess how this module addresses their security requirements. This section includes\r\nan incomplete list of security considerations that must be reviewed and understood before deploying **Hawk** on the server.\r\nMany of the protections provided in **Hawk** depends on whether and how they are used.\r\n\r\n### MAC Keys Transmission\r\n\r\n**Hawk** does not provide any mechanism for obtaining or transmitting the set of shared credentials required. Any mechanism used\r\nto obtain **Hawk** credentials must ensure that these transmissions are protected using transport-layer mechanisms such as TLS.\r\n\r\n### Confidentiality of Requests\r\n\r\nWhile **Hawk** provides a mechanism for verifying the integrity of HTTP requests, it provides no guarantee of request\r\nconfidentiality. Unless other precautions are taken, eavesdroppers will have full access to the request content. Servers should\r\ncarefully consider the types of data likely to be sent as part of such requests, and employ transport-layer security mechanisms\r\nto protect sensitive resources.\r\n\r\n### Spoofing by Counterfeit Servers\r\n\r\n**Hawk** provides limited verification of the server authenticity. When receiving a response back from the server, the server\r\nmay choose to include a response `Server-Authorization` header which the client can use to verify the response. However, it is up to\r\nthe server to determine when such measure is included, to up to the client to enforce that policy.\r\n\r\nA hostile party could take advantage of this by intercepting the client's requests and returning misleading or otherwise\r\nincorrect responses. Service providers should consider such attacks when developing services using this protocol, and should\r\nrequire transport-layer security for any requests where the authenticity of the resource server or of server responses is an issue.\r\n\r\n### Plaintext Storage of Credentials\r\n\r\nThe **Hawk** key functions the same way passwords do in traditional authentication systems. In order to compute the request MAC,\r\nthe server must have access to the key in plaintext form. This is in contrast, for example, to modern operating systems, which\r\nstore only a one-way hash of user credentials.\r\n\r\nIf an attacker were to gain access to these keys - or worse, to the server's database of all such keys - he or she would be able\r\nto perform any action on behalf of any resource owner. Accordingly, it is critical that servers protect these keys from unauthorized\r\naccess.\r\n\r\n### Entropy of Keys\r\n\r\nUnless a transport-layer security protocol is used, eavesdroppers will have full access to authenticated requests and request\r\nMAC values, and will thus be able to mount offline brute-force attacks to recover the key used. Servers should be careful to\r\nassign keys which are long enough, and random enough, to resist such attacks for at least the length of time that the **Hawk**\r\ncredentials are valid.\r\n\r\nFor example, if the credentials are valid for two weeks, servers should ensure that it is not possible to mount a brute force\r\nattack that recovers the key in less than two weeks. Of course, servers are urged to err on the side of caution, and use the\r\nlongest key reasonable.\r\n\r\nIt is equally important that the pseudo-random number generator (PRNG) used to generate these keys be of sufficiently high\r\nquality. Many PRNG implementations generate number sequences that may appear to be random, but which nevertheless exhibit\r\npatterns or other weaknesses which make cryptanalysis or brute force attacks easier. Implementers should be careful to use\r\ncryptographically secure PRNGs to avoid these problems.\r\n\r\n### Coverage Limitations\r\n\r\nThe request MAC only covers the HTTP `Host` header and optionally the `Content-Type` header. It does not cover any other headers\r\nwhich can often affect how the request body is interpreted by the server. If the server behavior is influenced by the presence\r\nor value of such headers, an attacker can manipulate the request headers without being detected. Implementers should use the\r\n`ext` feature to pass application-specific information via the `Authorization` header which is protected by the request MAC.\r\n\r\nThe response authentication, when performed, only covers the response payload, content-type, and the request information \r\nprovided by the client in it's request (method, resource, timestamp, nonce, etc.). It does not cover the HTTP status code or\r\nany other response header field (e.g. Location) which can affect the client's behaviour.\r\n\r\n### Future Time Manipulation\r\n\r\nThe protocol relies on a clock sync between the client and server. To accomplish this, the server informs the client of its\r\ncurrent time when an invalid timestamp is received.\r\n\r\nIf an attacker is able to manipulate this information and cause the client to use an incorrect time, it would be able to cause\r\nthe client to generate authenticated requests using time in the future. Such requests will fail when sent by the client, and will\r\nnot likely leave a trace on the server (given the common implementation of nonce, if at all enforced). The attacker will then\r\nbe able to replay the request at the correct time without detection.\r\n\r\nThe client must only use the time information provided by the server if:\r\n* it was delivered over a TLS connection and the server identity has been verified, or\r\n* the `tsm` MAC digest calculated using the same client credentials over the timestamp has been verified.\r\n\r\n### Client Clock Poisoning\r\n\r\nWhen receiving a request with a bad timestamp, the server provides the client with its current time. The client must never use\r\nthe time received from the server to adjust its own clock, and must only use it to calculate an offset for communicating with\r\nthat particular server.\r\n\r\n### Bewit Limitations\r\n\r\nSpecial care must be taken when issuing bewit credentials to third parties. Bewit credentials are valid until expiration and cannot\r\nbe revoked or limited without using other means. Whatever resource they grant access to will be completely exposed to anyone with\r\naccess to the bewit credentials which act as bearer credentials for that particular resource. While bewit usage is limited to GET\r\nrequests only and therefore cannot be used to perform transactions or change server state, it can still be used to expose private\r\nand sensitive information.\r\n\r\n\r\n# Frequently Asked Questions\r\n\r\n### Where is the protocol specification?\r\n\r\nIf you are looking for some prose explaining how all this works, **this is it**. **Hawk** is being developed as an open source\r\nproject instead of a standard. In other words, the [code](/hueniverse/hawk/tree/master/lib) is the specification. Not sure about\r\nsomething? Open an issue!\r\n\r\n### Is it done?\r\n\r\nAt if version 0.10.0, **Hawk** is feature-complete. However, until this module reaches version 1.0.0 it is considered experimental\r\nand is likely to change. This also means your feedback and contribution are very welcome. Feel free to open issues with questions\r\nand suggestions.\r\n\r\n### Where can I find **Hawk** implementations in other languages?\r\n\r\n**Hawk**'s only reference implementation is provided in JavaScript as a node.js module. However, others are actively porting it to other\r\nplatforms. There is already a [PHP](https://github.com/alexbilbie/PHP-Hawk),\r\n[.NET](https://github.com/pcibraro/hawknet), and [JAVA](https://github.com/wealdtech/hawk) libraries available. The full list\r\nis maintained [here](https://github.com/hueniverse/hawk/issues?labels=port). Please add an issue if you are working on another\r\nport. A cross-platform test-suite is in the works.\r\n\r\n### Why isn't the algorithm part of the challenge or dynamically negotiated?\r\n\r\nThe algorithm used is closely related to the key issued as different algorithms require different key sizes (and other\r\nrequirements). While some keys can be used for multiple algorithm, the protocol is designed to closely bind the key and algorithm\r\ntogether as part of the issued credentials.\r\n\r\n### Why is Host and Content-Type the only headers covered by the request MAC?\r\n\r\nIt is really hard to include other headers. Headers can be changed by proxies and other intermediaries and there is no\r\nwell-established way to normalize them. Many platforms change the case of header field names and values. The only\r\nstraight-forward solution is to include the headers in some blob (say, base64 encoded JSON) and include that with the request,\r\nan approach taken by JWT and other such formats. However, that design violates the HTTP header boundaries, repeats information,\r\nand introduces other security issues because firewalls will not be aware of these \"hidden\" headers. In addition, any information\r\nrepeated must be compared to the duplicated information in the header and therefore only moves the problem elsewhere.\r\n\r\n### Why not just use HTTP Digest?\r\n\r\nDigest requires pre-negotiation to establish a nonce. This means you can't just make a request - you must first send\r\na protocol handshake to the server. This pattern has become unacceptable for most web services, especially mobile\r\nwhere extra round-trip are costly.\r\n\r\n### Why bother with all this nonce and timestamp business?\r\n\r\n**Hawk** is an attempt to find a reasonable, practical compromise between security and usability. OAuth 1.0 got timestamp\r\nand nonces halfway right but failed when it came to scalability and consistent developer experience. **Hawk** addresses\r\nit by requiring the client to sync its clock, but provides it with tools to accomplish it.\r\n\r\nIn general, replay protection is a matter of application-specific threat model. It is less of an issue on a TLS-protected\r\nsystem where the clients are implemented using best practices and are under the control of the server. Instead of dropping\r\nreplay protection, **Hawk** offers a required time window and an optional nonce verification. Together, it provides developers\r\nwith the ability to decide how to enforce their security policy without impacting the client's implementation.\r\n\r\n### What are `app` and `dlg` in the authorization header and normalized mac string?\r\n\r\nThe original motivation for **Hawk** was to replace the OAuth 1.0 use cases. This included both a simple client-server mode which\r\nthis module is specifically designed for, and a delegated access mode which is being developed separately in\r\n[Oz](https://github.com/hueniverse/oz). In addition to the **Hawk** use cases, Oz requires another attribute: the application id `app`.\r\nThis provides binding between the credentials and the application in a way that prevents an attacker from tricking an application\r\nto use credentials issued to someone else. It also has an optional 'delegated-by' attribute `dlg` which is the application id of the\r\napplication the credentials were directly issued to. The goal of these two additions is to allow Oz to utilize **Hawk** directly,\r\nbut with the additional security of delegated credentials.\r\n\r\n### What is the purpose of the static strings used in each normalized MAC input?\r\n\r\nWhen calculating a hash or MAC, a static prefix (tag) is added. The prefix is used to prevent MAC values from being\r\nused or reused for a purpose other than what they were created for (i.e. prevents switching MAC values between a request,\r\nresponse, and a bewit use cases). It also protects against expliots created after a potential change in how the protocol\r\ncreates the normalized string. For example, if a future version would switch the order of nonce and timestamp, it\r\ncan create an exploit opportunity for cases where the nonce is similar in format to a timestamp.\r\n\r\n### Does **Hawk** have anything to do with OAuth?\r\n\r\nShort answer: no.\r\n\r\n**Hawk** was originally proposed as the OAuth MAC Token specification. However, the OAuth working group in its consistent\r\nincompetence failed to produce a final, usable solution to address one of the most popular use cases of OAuth 1.0 - using it\r\nto authenticate simple client-server transactions (i.e. two-legged). As you can guess, the OAuth working group is still hard\r\nat work to produce more garbage.\r\n\r\n**Hawk** provides a simple HTTP authentication scheme for making client-server requests. It does not address the OAuth use case\r\nof delegating access to a third party. If you are looking for an OAuth alternative, check out [Oz](/hueniverse/oz).\r\n\r\n\r\n# Acknowledgements\r\n\r\n**Hawk** is a derivative work of the [HTTP MAC Authentication Scheme](http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05) proposal\r\nco-authored by Ben Adida, Adam Barth, and Eran Hammer, which in turn was based on the OAuth 1.0 community specification.\r\n\r\nSpecial thanks to Ben Laurie for his always insightful feedback and advice.\r\n\r\nThe **Hawk** logo was created by [Chris Carrasco](http://chriscarrasco.com).\r\n", + "readmeFilename": "README.md", + "_id": "hawk@0.10.2", + "dist": { + "shasum": "ebfc9448d2ff8821da7723faf735255f9c1833de" + }, + "_from": "hawk@~0.10.2", + "_resolved": "https://registry.npmjs.org/hawk/-/hawk-0.10.2.tgz" +} diff --git a/node_modules/request/node_modules/hawk/test/client.js b/node_modules/request/node_modules/hawk/test/client.js new file mode 100755 index 000000000..b7b2bab17 --- /dev/null +++ b/node_modules/request/node_modules/hawk/test/client.js @@ -0,0 +1,208 @@ +// Load modules + +var Url = require('url'); +var Lab = require('lab'); +var Hawk = require('../lib'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect; +var before = Lab.before; +var after = Lab.after; +var describe = Lab.experiment; +var it = Lab.test; + + +describe('Hawk', function () { + + describe('client', function () { + + describe('#header', function () { + + it('should return a valid authorization header (sha1)', function (done) { + + var credentials = { + id: '123456', + key: '2983d45yun89q', + algorithm: 'sha1' + }; + + var header = Hawk.client.header('http://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about' }).field; + expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="bsvY3IfUllw6V5rvk4tStEvpBhE=", ext="Bazinga!", mac="qbf1ZPG/r/e06F4ht+T77LXi5vw="'); + done(); + }); + + it('should return a valid authorization header (sha256)', function (done) { + + var credentials = { + id: '123456', + key: '2983d45yun89q', + algorithm: 'sha256' + }; + + var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field; + expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ext="Bazinga!", mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="'); + done(); + }); + + it('should return a valid authorization header (no ext)', function (done) {
+ + var credentials = {
+ id: '123456', + key: '2983d45yun89q', + algorithm: 'sha256'
+ }; + + var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, timestamp: 1353809207, nonce: 'Ygvqdz', payload: 'something to write about', contentType: 'text/plain' }).field; + expect(header).to.equal('Hawk id="123456", ts="1353809207", nonce="Ygvqdz", hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="'); + done();
+ }); + + it('should return an empty authorization header on missing options', function (done) { + + var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST').field; + expect(header).to.equal(''); + done(); + }); + + it('should return an empty authorization header on invalid credentials', function (done) { + + var credentials = { + key: '2983d45yun89q', + algorithm: 'sha256' + }; + + var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, ext: 'Bazinga!', timestamp: 1353809207 }).field; + expect(header).to.equal(''); + done(); + }); + + it('should return an empty authorization header on invalid algorithm', function (done) { + + var credentials = { + id: '123456', + key: '2983d45yun89q', + algorithm: 'hmac-sha-0' + }; + + var header = Hawk.client.header('https://example.net/somewhere/over/the/rainbow', 'POST', { credentials: credentials, payload: 'something, anything!', ext: 'Bazinga!', timestamp: 1353809207 }).field; + expect(header).to.equal(''); + done(); + }); + }); + + describe('#authenticate', function () { + + it('should return false on invalid header', function (done) { + + var res = { + headers: { + 'server-authorization': 'Hawk mac="abc", bad="xyz"' + } + }; + + expect(Hawk.client.authenticate(res, {})).to.equal(false); + done(); + }); + + it('should return false on invalid mac', function (done) { + + var res = { + headers: { + 'content-type': 'text/plain', + 'server-authorization': 'Hawk mac="_IJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"' + } + }; + + var artifacts = { + method: 'POST', + host: 'example.com', + port: '8080', + resource: '/resource/4?filter=a', + ts: '1362336900', + nonce: 'eb5S_L', + hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=', + ext: 'some-app-data', + app: undefined, + dlg: undefined, + mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=', + id: '123456', + credentials: + { + id: '123456', + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: 'sha256', + user: 'steve' + } + }; + + expect(Hawk.client.authenticate(res, artifacts)).to.equal(false); + done(); + }); + + it('should return true on ignoring hash', function (done) { + + var res = { + headers: { + 'content-type': 'text/plain', + 'server-authorization': 'Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"' + } + }; + + var artifacts = { + method: 'POST', + host: 'example.com', + port: '8080', + resource: '/resource/4?filter=a', + ts: '1362336900', + nonce: 'eb5S_L', + hash: 'nJjkVtBE5Y/Bk38Aiokwn0jiJxt/0S2WRSUwWLCf5xk=', + ext: 'some-app-data', + app: undefined, + dlg: undefined, + mac: 'BlmSe8K+pbKIb6YsZCnt4E1GrYvY1AaYayNR82dGpIk=', + id: '123456', + credentials: + { + id: '123456', + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: 'sha256', + user: 'steve' + } + }; + + expect(Hawk.client.authenticate(res, artifacts)).to.equal(true); + done(); + }); + + it('should fail on invalid WWW-Authenticate header format', function (done) { + + var header = 'Hawk ts="1362346425875", tsm="PhwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", x="Stale timestamp"'; + expect(Hawk.client.authenticate({ headers: { 'www-authenticate': header } }, {})).to.equal(false); + done(); + }); + + it('should fail on invalid WWW-Authenticate header format', function (done) { + + var artifacts = { + credentials: { + id: '123456', + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: 'sha256', + user: 'steve' + } + }; + + var header = 'Hawk ts="1362346425875", tsm="hwayS28vtnn3qbv0mqRBYSXebN/zggEtucfeZ620Zo=", error="Stale timestamp"'; + expect(Hawk.client.authenticate({ headers: { 'www-authenticate': header } }, artifacts)).to.equal(false); + done(); + }); + }); + }); +}); diff --git a/node_modules/request/node_modules/hawk/test/crypto.js b/node_modules/request/node_modules/hawk/test/crypto.js new file mode 100755 index 000000000..74c081072 --- /dev/null +++ b/node_modules/request/node_modules/hawk/test/crypto.js @@ -0,0 +1,86 @@ +// Load modules + +var Lab = require('lab');
+var Hawk = require('../lib'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+ + +describe('Hawk', function () { + + describe('Crypto', function () { + + describe('#generateNormalizedString', function () { + + it('should return a valid normalized string', function (done) { + + expect(Hawk.crypto.generateNormalizedString('header', { + credentials: { + key: 'dasdfasdf', + algorithm: 'sha256' + }, + ts: 1357747017, + nonce: 'k3k4j5', + method: 'GET', + resource: '/resource/something', + host: 'example.com', + port: 8080 + })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\n\n\n'); + + done(); + }); + + it('should return a valid normalized string (ext)', function (done) { + + expect(Hawk.crypto.generateNormalizedString('header', { + credentials: { + key: 'dasdfasdf', + algorithm: 'sha256' + }, + ts: 1357747017, + nonce: 'k3k4j5', + method: 'GET', + resource: '/resource/something', + host: 'example.com', + port: 8080, + ext: 'this is some app data' + })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\n\nthis is some app data\n'); + + done(); + }); + + it('should return a valid normalized string (payload + ext)', function (done) { + + expect(Hawk.crypto.generateNormalizedString('header', { + credentials: { + key: 'dasdfasdf', + algorithm: 'sha256' + }, + ts: 1357747017, + nonce: 'k3k4j5', + method: 'GET', + resource: '/resource/something', + host: 'example.com', + port: 8080, + hash: 'U4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=', + ext: 'this is some app data' + })).to.equal('hawk.1.header\n1357747017\nk3k4j5\nGET\n/resource/something\nexample.com\n8080\nU4MKKSmiVxk37JCCrAVIjV/OhB3y+NdwoCr6RShbVkE=\nthis is some app data\n'); + + done(); + }); + }); + }); +}); + diff --git a/node_modules/request/node_modules/hawk/test/index.js b/node_modules/request/node_modules/hawk/test/index.js new file mode 100755 index 000000000..7217eaa73 --- /dev/null +++ b/node_modules/request/node_modules/hawk/test/index.js @@ -0,0 +1,316 @@ +// Load modules + +var Url = require('url'); +var Lab = require('lab');
+var Hawk = require('../lib'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+ + +describe('Hawk', function () { + + var credentialsFunc = function (id, callback) { + + var credentials = { + id: id, + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: (id === '1' ? 'sha1' : 'sha256'), + user: 'steve' + }; + + return callback(null, credentials); + }; + + it('should generate a header then successfully parse it (configuration)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080 + }; + + credentialsFunc('123456', function (err, credentials) { + + req.authorization = Hawk.client.header(Url.parse('http://example.com:8080/resource/4?filter=a'), req.method, { credentials: credentials, ext: 'some-app-data' }).field; + expect(req.authorization).to.exist; + + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(artifacts.ext).to.equal('some-app-data'); + done(); + }); + }); + }); + + it('should generate a header then successfully parse it (node request)', function (done) { + + var req = { + method: 'POST', + url: '/resource/4?filter=a', + headers: { + host: 'example.com:8080', + 'content-type': 'text/plain;x=y' + } + }; + + var payload = 'some not so random text'; + + credentialsFunc('123456', function (err, credentials) { + + var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] }); + req.headers.authorization = reqHeader.field; + + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(artifacts.ext).to.equal('some-app-data'); + expect(Hawk.server.authenticatePayload(payload, credentials, artifacts.hash, req.headers['content-type'])).to.equal(true); + + var res = { + headers: { + 'content-type': 'text/plain' + } + }; + + res.headers['server-authorization'] = Hawk.server.header(artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' }); + expect(res.headers['server-authorization']).to.exist; + + expect(Hawk.client.authenticate(res, artifacts, { payload: 'some reply' })).to.equal(true); + done(); + }); + }); + }); + + it('should generate a header then successfully parse it (no server header options)', function (done) {
+ + var req = {
+ method: 'POST', + url: '/resource/4?filter=a', + headers: {
+ host: 'example.com:8080', + 'content-type': 'text/plain;x=y'
+ }
+ }; + + var payload = 'some not so random text'; + + credentialsFunc('123456', function (err, credentials) {
+ + var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] }); + req.headers.authorization = reqHeader.field; + + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+ + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(artifacts.ext).to.equal('some-app-data'); + expect(Hawk.server.authenticatePayload(payload, credentials, artifacts.hash, req.headers['content-type'])).to.equal(true); + + var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ }
+ }; + + res.headers['server-authorization'] = Hawk.server.header(artifacts); + expect(res.headers['server-authorization']).to.exist; + + expect(Hawk.client.authenticate(res, artifacts)).to.equal(true); + done();
+ });
+ });
+ }); + + it('should generate a header then fails to parse it (missing server header hash)', function (done) {
+ + var req = {
+ method: 'POST', + url: '/resource/4?filter=a', + headers: {
+ host: 'example.com:8080', + 'content-type': 'text/plain;x=y'
+ }
+ }; + + var payload = 'some not so random text'; + + credentialsFunc('123456', function (err, credentials) {
+ + var reqHeader = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', payload: payload, contentType: req.headers['content-type'] }); + req.headers.authorization = reqHeader.field; + + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+ + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(artifacts.ext).to.equal('some-app-data'); + expect(Hawk.server.authenticatePayload(payload, credentials, artifacts.hash, req.headers['content-type'])).to.equal(true); + + var res = {
+ headers: {
+ 'content-type': 'text/plain'
+ }
+ }; + + res.headers['server-authorization'] = Hawk.server.header(artifacts); + expect(res.headers['server-authorization']).to.exist; + + expect(Hawk.client.authenticate(res, artifacts, { payload: 'some reply' })).to.equal(false); + done();
+ });
+ });
+ }); + + it('should generate a header then successfully parse it (with hash)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080 + }; + + credentialsFunc('123456', function (err, credentials) { + + req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field; + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(artifacts.ext).to.equal('some-app-data'); + done(); + }); + }); + }); + + it('should generate a header then successfully parse it then validate payload', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080 + }; + + credentialsFunc('123456', function (err, credentials) { + + req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field; + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(artifacts.ext).to.equal('some-app-data'); + expect(Hawk.server.authenticatePayload('hola!', credentials, artifacts.hash)).to.be.true; + expect(Hawk.server.authenticatePayload('hello!', credentials, artifacts.hash)).to.be.false; + done(); + }); + }); + }); + + it('should generate a header then successfully parse it (app)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080 + }; + + credentialsFunc('123456', function (err, credentials) { + + req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased' }).field; + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(artifacts.ext).to.equal('some-app-data'); + expect(artifacts.app).to.equal('asd23ased'); + done(); + }); + }); + }); + + it('should generate a header then successfully parse it (app, dlg)', function (done) {
+ + var req = {
+ method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080
+ }; + + credentialsFunc('123456', function (err, credentials) {
+ + req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data', app: 'asd23ased', dlg: '23434szr3q4d' }).field; + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
+ + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(artifacts.ext).to.equal('some-app-data'); + expect(artifacts.app).to.equal('asd23ased'); + expect(artifacts.dlg).to.equal('23434szr3q4d'); + done();
+ });
+ });
+ }); + + it('should generate a header then fail authentication due to bad hash', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080 + }; + + credentialsFunc('123456', function (err, credentials) { + + req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, payload: 'hola!', ext: 'some-app-data' }).field; + Hawk.server.authenticate(req, credentialsFunc, { payload: 'byebye!' }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Bad payload hash'); + done(); + }); + }); + }); + + it('should generate a header for one resource then fail to authenticate another', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080 + }; + + credentialsFunc('123456', function (err, credentials) { + + req.authorization = Hawk.client.header('http://example.com:8080/resource/4?filter=a', req.method, { credentials: credentials, ext: 'some-app-data' }).field; + req.url = '/something/else'; + + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(credentials).to.exist; + done(); + }); + }); + }); +}); diff --git a/node_modules/request/node_modules/hawk/test/readme.js b/node_modules/request/node_modules/hawk/test/readme.js new file mode 100755 index 000000000..05040c549 --- /dev/null +++ b/node_modules/request/node_modules/hawk/test/readme.js @@ -0,0 +1,98 @@ +// Load modules + +var Lab = require('lab');
+var Hoek = require('hoek'); +var Hawk = require('../lib'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect; +var before = Lab.before; +var after = Lab.after; +var describe = Lab.experiment; +var it = Lab.test; + + +describe('Hawk', function () { + + describe('README', function () { + + describe('core', function () { + + var credentials = { + id: 'dh37fgj492je', + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: 'sha256' + }; + + var options = { + credentials: credentials, + timestamp: 1353832234, + nonce: 'j4h3g2', + ext: 'some-app-ext-data' + }; + + it('should generate a header protocol example', function (done) { + + var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', options).field; + + expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="'); + done(); + }); + + it('should generate a normalized string protocol example', function (done) { + + var normalized = Hawk.crypto.generateNormalizedString('header', { + credentials: credentials, + ts: options.timestamp, + nonce: options.nonce, + method: 'GET', + resource: '/resource?a=1&b=2', + host: 'example.com', + port: 8000, + ext: options.ext + }); + + expect(normalized).to.equal('hawk.1.header\n1353832234\nj4h3g2\nGET\n/resource?a=1&b=2\nexample.com\n8000\n\nsome-app-ext-data\n'); + done(); + }); + + var payloadOptions = Hoek.clone(options); + payloadOptions.payload = 'Thank you for flying Hawk'; + payloadOptions.contentType = 'text/plain'; + + it('should generate a header protocol example (with payload)', function (done) { + + var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'POST', payloadOptions).field; + + expect(header).to.equal('Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="'); + done(); + }); + + it('should generate a normalized string protocol example (with payload)', function (done) { + + var normalized = Hawk.crypto.generateNormalizedString('header', { + credentials: credentials, + ts: options.timestamp, + nonce: options.nonce, + method: 'POST', + resource: '/resource?a=1&b=2', + host: 'example.com', + port: 8000, + hash: Hawk.crypto.calculateHash(payloadOptions.payload, credentials.algorithm, payloadOptions.contentType), + ext: options.ext + }); + + expect(normalized).to.equal('hawk.1.header\n1353832234\nj4h3g2\nPOST\n/resource?a=1&b=2\nexample.com\n8000\nYi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=\nsome-app-ext-data\n'); + done(); + }); + }); + }); +}); + diff --git a/node_modules/request/node_modules/hawk/test/server.js b/node_modules/request/node_modules/hawk/test/server.js new file mode 100755 index 000000000..d2674abcc --- /dev/null +++ b/node_modules/request/node_modules/hawk/test/server.js @@ -0,0 +1,642 @@ +// Load modules + +var Url = require('url'); +var Lab = require('lab');
+var Hawk = require('../lib'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+ + +describe('Hawk', function () { + + describe('server', function () { + + var credentialsFunc = function (id, callback) { + + var credentials = { + id: id, + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: (id === '1' ? 'sha1' : 'sha256'), + user: 'steve' + }; + + return callback(null, credentials); + }; + + describe('#authenticate', function () { + + it('should parse a valid authentication header (sha1)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="1", ts="1353788437", nonce="k3j4h2", mac="zy79QQ5/EYFmQqutVnYb73gAc/U=", ext="hello"', + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + done(); + }); + }); + + it('should parse a valid authentication header (sha256)', function (done) { + + var req = { + method: 'GET', + url: '/resource/1?b=1&a=2', + host: 'example.com', + port: 8000, + authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"', + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353832234000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + done(); + }); + }); + + it('should parse a valid authentication header (POST with payload)', function (done) { + + var req = { + method: 'POST', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123456", ts="1357926341", nonce="1AwuJD", hash="qAiXIVv+yjDATneWxZP2YCTa9aHRgQdnH9b3Wc+o3dg=", ext="some-app-data", mac="UeYcj5UoTVaAWXNvJfLVia7kU3VabxCqrccXP8sUGC4="', + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1357926341000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + done(); + }); + }); + + it('should fail on missing hash', function (done) { + + var req = { + method: 'GET', + url: '/resource/1?b=1&a=2', + host: 'example.com', + port: 8000, + authorization: 'Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", mac="m8r1rHbXN6NgO+KIIhjO7sFRyd78RNGVUwehe8Cp2dU=", ext="some-app-data"', + }; + + Hawk.server.authenticate(req, credentialsFunc, { payload: 'body', localtimeOffsetMsec: 1353832234000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Missing required payload hash'); + done(); + }); + }); + + it('should fail on a stale timestamp', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123456", ts="1362337299", nonce="UzmxSs", ext="some-app-data", mac="wnNUxchvvryMH2RxckTdZ/gY3ijzvccx4keVvELC61w="', + }; + + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Stale timestamp'); + var header = err.response.headers['WWW-Authenticate']; + var ts = header.match(/^Hawk ts\=\"(\d+)\"\, tsm\=\"([^\"]+)\"\, error=\"Stale timestamp\"$/); + var now = Hawk.utils.now(); + expect(parseInt(ts[1], 10)).to.be.within(now - 1, now + 1); + + var res = { + headers: { + 'www-authenticate': header + } + }; + + expect(Hawk.client.authenticate(res, artifacts)).to.equal(true); + done(); + }); + }); + + it('should fail on a replay', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="bXx7a7p1h9QYQNZ8x7QhvDQym8ACgab4m3lVSFn4DBw=", ext="hello"', + }; + + var memoryCache = {}; + var options = { + localtimeOffsetMsec: 1353788437000 - Hawk.utils.now(), + nonceFunc: function (nonce, ts, callback) { + + if (memoryCache[nonce]) { + return callback(new Error()); + } + + memoryCache[nonce] = true; + return callback(); + } + }; + + Hawk.server.authenticate(req, credentialsFunc, options, function (err, credentials, artifacts) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + + Hawk.server.authenticate(req, credentialsFunc, options, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid nonce'); + done(); + }); + }); + }); + + it('should fail on an invalid authentication header: wrong scheme', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Basic asdasdasdasd' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.not.exist; + done(); + }); + }); + + it('should fail on an invalid authentication header: no scheme', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: '!@#' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid header syntax'); + done(); + }); + }); + + it('should fail on an missing authorization header', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080 + }; + + Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.isMissing).to.equal(true); + done(); + }); + }); + + it('should fail on an missing host header', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + headers: { + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + } + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid Host header'); + done(); + }); + }); + + it('should fail on an missing authorization attribute (id)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Missing attributes'); + done(); + }); + }); + + it('should fail on an missing authorization attribute (ts)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Missing attributes'); + done(); + }); + }); + + it('should fail on an missing authorization attribute (nonce)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Missing attributes'); + done(); + }); + }); + + it('should fail on an missing authorization attribute (mac)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Missing attributes'); + done(); + }); + }); + + it('should fail on an unknown authorization attribute', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", x="3", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Unknown attribute: x'); + done(); + }); + }); + + it('should fail on an bad authorization header format', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123\\", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Bad header format'); + done(); + }); + }); + + it('should fail on an bad authorization attribute value', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="\t", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Bad attribute value: id'); + done(); + }); + }); + + it('should fail on an empty authorization attribute value', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Bad attribute value: id'); + done(); + }); + }); + + it('should fail on duplicated authorization attribute key', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", id="456", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Duplicate attribute: id'); + done(); + }); + }); + + it('should fail on an invalid authorization header format', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk' + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid header syntax'); + done(); + }); + }); + + it('should fail on an bad host header (missing host)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + headers: { + host: ':8080', + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + } + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid Host header'); + done(); + }); + }); + + it('should fail on an bad host header (pad port)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + headers: { + host: 'example.com:something', + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + } + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid Host header'); + done(); + }); + }); + + it('should fail on credentialsFunc error', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + var credentialsFunc = function (id, callback) { + + return callback(new Error('Unknown user')); + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.message).to.equal('Unknown user'); + done(); + }); + }); + + it('should fail on missing credentials', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + var credentialsFunc = function (id, callback) { + + return callback(null, null); + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Unknown credentials'); + done(); + }); + }); + + it('should fail on invalid credentials', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + var credentialsFunc = function (id, callback) { + + var credentials = { + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + user: 'steve' + }; + + return callback(null, credentials); + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.message).to.equal('Invalid credentials'); + expect(err.response.payload.message).to.equal('An internal server error occurred'); + done(); + }); + }); + + it('should fail on unknown credentials algorithm', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcUyW6EEgUH4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + var credentialsFunc = function (id, callback) { + + var credentials = { + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: 'hmac-sha-0', + user: 'steve' + }; + + return callback(null, credentials); + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.message).to.equal('Unknown algorithm'); + expect(err.response.payload.message).to.equal('An internal server error occurred'); + done(); + }); + }); + + it('should fail on unknown bad mac', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080, + authorization: 'Hawk id="123", ts="1353788437", nonce="k3j4h2", mac="/qwS4UjfVWMcU4jlr7T/wuKe3dKijvTvSos=", ext="hello"' + }; + + var credentialsFunc = function (id, callback) { + + var credentials = { + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: 'sha256', + user: 'steve' + }; + + return callback(null, credentials); + }; + + Hawk.server.authenticate(req, credentialsFunc, { localtimeOffsetMsec: 1353788437000 - Hawk.utils.now() }, function (err, credentials, artifacts) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Bad mac'); + done(); + }); + }); + }); + + describe('#header', function () { + + it('should return an empty authorization header on missing options', function (done) { + + var header = Hawk.server.header(); + expect(header).to.equal(''); + done(); + }); + + it('should return an empty authorization header on invalid credentials', function (done) { + + var artifacts = { + credentials: { + key: '2983d45yun89q' + } + }; + + var header = Hawk.server.header(artifacts); + expect(header).to.equal(''); + done(); + }); + + it('should return an empty authorization header on invalid algorithm', function (done) { + + var artifacts = { + id: '123456', + credentials: { + key: '2983d45yun89q', + algorithm: 'hmac-sha-0' + } + }; + + var header = Hawk.server.header(artifacts); + expect(header).to.equal(''); + done(); + }); + }); + }); +}); diff --git a/node_modules/request/node_modules/hawk/test/uri.js b/node_modules/request/node_modules/hawk/test/uri.js new file mode 100755 index 000000000..0e9f11fc2 --- /dev/null +++ b/node_modules/request/node_modules/hawk/test/uri.js @@ -0,0 +1,457 @@ +// Load modules + +var Http = require('http'); +var Lab = require('lab');
+var Hawk = require('../lib'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect;
+var before = Lab.before;
+var after = Lab.after;
+var describe = Lab.experiment;
+var it = Lab.test;
+ + +describe('Hawk', function () { + + describe('Uri', function () { + + var credentialsFunc = function (id, callback) { + + var credentials = { + id: id, + key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', + algorithm: 'sha256', + user: 'steve' + }; + + return callback(null, credentials); + }; + + it('should generate a bewit then successfully authenticate it', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?a=1&b=2', + host: 'example.com', + port: 80 + }; + + credentialsFunc('123456', function (err, credentials) { + + var bewit = Hawk.uri.getBewit('http://example.com/resource/4?a=1&b=2', { credentials: credentials, ttlSec: 60 * 60 * 24 * 365 * 100, ext: 'some-app-data' }); + req.url += '&bewit=' + bewit; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(attributes.ext).to.equal('some-app-data'); + done(); + }); + }); + }); + + it('should generate a bewit then successfully authenticate it (no ext)', function (done) {
+ + var req = {
+ method: 'GET', + url: '/resource/4?a=1&b=2', + host: 'example.com', + port: 80
+ }; + + credentialsFunc('123456', function (err, credentials) {
+ + var bewit = Hawk.uri.getBewit('http://example.com/resource/4?a=1&b=2', { credentials: credentials, ttlSec: 60 * 60 * 24 * 365 * 100 }); + req.url += '&bewit=' + bewit; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
+ + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + done();
+ });
+ });
+ }); + + it('should successfully authenticate a request (last param)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?a=1&b=2&bewit=MTIzNDU2XDQ1MTE0ODQ2MjFcMzFjMmNkbUJFd1NJRVZDOVkva1NFb2c3d3YrdEVNWjZ3RXNmOGNHU2FXQT1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(attributes.ext).to.equal('some-app-data'); + done(); + }); + }); + + it('should successfully authenticate a request (first param)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2MjFcMzFjMmNkbUJFd1NJRVZDOVkva1NFb2c3d3YrdEVNWjZ3RXNmOGNHU2FXQT1cc29tZS1hcHAtZGF0YQ&a=1&b=2', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(attributes.ext).to.equal('some-app-data'); + done(); + }); + }); + + it('should successfully authenticate a request (only param)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2NDFcZm1CdkNWT3MvcElOTUUxSTIwbWhrejQ3UnBwTmo4Y1VrSHpQd3Q5OXJ1cz1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.not.exist; + expect(credentials.user).to.equal('steve'); + expect(attributes.ext).to.equal('some-app-data'); + done(); + }); + }); + + it('should fail on multiple authentication', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MTE0ODQ2NDFcZm1CdkNWT3MvcElOTUUxSTIwbWhrejQ3UnBwTmo4Y1VrSHpQd3Q5OXJ1cz1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080, + authorization: 'Basic asdasdasdasd' + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Multiple authentications'); + done(); + }); + }); + + it('should fail on method other than GET', function (done) { + + credentialsFunc('123456', function (err, credentials) { + + var req = { + method: 'POST', + url: '/resource/4?filter=a', + host: 'example.com', + port: 8080 + }; + + var exp = Math.floor(Hawk.utils.now() / 1000) + 60; + var ext = 'some-app-data'; + var mac = Hawk.crypto.calculateMac('bewit', { + credentials: credentials, + timestamp: exp, + nonce: '', + method: req.method, + resource: req.url, + host: req.host, + port: req.port, + ext: ext + }); + + var bewit = credentials.id + '\\' + exp + '\\' + mac + '\\' + ext; + + req.url += '&bewit=' + Hawk.utils.base64urlEncode(bewit); + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid method'); + done(); + }); + }); + }); + + it('should fail on invalid host header', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ', + headers: { + host: 'example.com:something' + } + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid Host header'); + done(); + }); + }); + + it('should fail on empty bewit', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Empty bewit'); + expect(err.isMissing).to.not.exist; + done(); + }); + }); + + it('should fail on invalid bewit', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=*', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid bewit encoding'); + expect(err.isMissing).to.not.exist; + done(); + }); + }); + + it('should fail on missing bewit', function (done) { + + var req = { + method: 'GET', + url: '/resource/4', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.not.exist; + expect(err.isMissing).to.equal(true); + done(); + }); + }); + + it('should fail on invalid bewit structure', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=abc', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Invalid bewit structure'); + done(); + }); + }); + + it('should fail on empty bewit attribute', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=YVxcY1xk', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Missing bewit attributes'); + done(); + }); + }); + + it('should fail on expired access', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?a=1&b=2&bewit=MTIzNDU2XDEzNTY0MTg1ODNcWk1wZlMwWU5KNHV0WHpOMmRucTRydEk3NXNXTjFjeWVITTcrL0tNZFdVQT1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Access expired'); + done(); + }); + }); + + it('should fail on credentials function error', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, function (id, callback) { callback(Hawk.error.badRequest('Boom')); }, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Boom'); + done(); + }); + }); + + it('should fail on null credentials function response', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, function (id, callback) { callback(null, null); }, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Unknown credentials'); + done(); + }); + }); + + it('should fail on invalid credentials function response', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, function (id, callback) { callback(null, {}); }, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.message).to.equal('Invalid credentials'); + done(); + }); + }); + + it('should fail on invalid credentials function response (unknown algorithm)', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, function (id, callback) { callback(null, { key: 'xxx', algorithm: 'xxx' }); }, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.message).to.equal('Unknown algorithm'); + done(); + }); + }); + + it('should fail on expired access', function (done) { + + var req = { + method: 'GET', + url: '/resource/4?bewit=MTIzNDU2XDQ1MDk5OTE3MTlcTUE2eWkwRWRwR0pEcWRwb0JkYVdvVDJrL0hDSzA1T0Y3MkhuZlVmVy96Zz1cc29tZS1hcHAtZGF0YQ', + host: 'example.com', + port: 8080 + }; + + Hawk.uri.authenticate(req, function (id, callback) { callback(null, { key: 'xxx', algorithm: 'sha256' }); }, {}, function (err, credentials, attributes) { + + expect(err).to.exist; + expect(err.response.payload.message).to.equal('Bad mac'); + done(); + }); + }); + }); + + describe('#getBewit', function () { + + it('should return a valid bewit value', function (done) { + + var credentials = { + id: '123456', + key: '2983d45yun89q', + algorithm: 'sha256' + }; + + var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, localtimeOffsetMsec: 1356420407232 - Hawk.utils.now(), ext: 'xandyandz' }); + expect(bewit).to.equal('MTIzNDU2XDEzNTY0MjA3MDdca3NjeHdOUjJ0SnBQMVQxekRMTlBiQjVVaUtJVTl0T1NKWFRVZEc3WDloOD1ceGFuZHlhbmR6'); + done(); + }); + + it('should return an empty bewit on invalid credentials', function (done) { + + var credentials = { + key: '2983d45yun89q', + algorithm: 'sha256' + }; + + var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 3000, ext: 'xandyandz' }); + expect(bewit).to.equal(''); + done(); + }); + + it('should return an empty bewit on invalid algorithm', function (done) { + + var credentials = { + id: '123456', + key: '2983d45yun89q', + algorithm: 'hmac-sha-0' + }; + + var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow', { credentials: credentials, ttlSec: 300, ext: 'xandyandz' }); + expect(bewit).to.equal(''); + done(); + }); + + it('should return an empty bewit on missing options', function (done) { + + var credentials = { + id: '123456', + key: '2983d45yun89q', + algorithm: 'hmac-sha-0' + }; + + var bewit = Hawk.uri.getBewit('https://example.com/somewhere/over/the/rainbow'); + expect(bewit).to.equal(''); + done(); + }); + }); +}); + diff --git a/node_modules/request/node_modules/hawk/test/utils.js b/node_modules/request/node_modules/hawk/test/utils.js new file mode 100755 index 000000000..97c938a79 --- /dev/null +++ b/node_modules/request/node_modules/hawk/test/utils.js @@ -0,0 +1,73 @@ +// Load modules + +var Lab = require('lab'); +var Hawk = require('../lib'); +var Package = require('../package.json'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Lab.expect; +var before = Lab.before; +var after = Lab.after; +var describe = Lab.experiment; +var it = Lab.test; + + +describe('Hawk', function () { + + describe('Utils', function () { + + describe('#parseHost', function () {
+
+ it('returns port 80 for non tls node request', function (done) {
+
+ var req = {
+ method: 'POST', + url: '/resource/4?filter=a', + headers: {
+ host: 'example.com', + 'content-type': 'text/plain;x=y'
+ }
+ }; + + expect(Hawk.utils.parseHost(req, 'Host').port).to.equal(80);
+ done();
+ });
+
+ it('returns port 443 for non tls node request', function (done) {
+
+ var req = {
+ method: 'POST', + url: '/resource/4?filter=a', + headers: {
+ host: 'example.com', + 'content-type': 'text/plain;x=y'
+ },
+ connection: {
+ encrypted: true
+ }
+ }; + + expect(Hawk.utils.parseHost(req, 'Host').port).to.equal(443);
+ done();
+ });
+ }); + + describe('#version', function () { + + it('returns the correct package version number', function (done) { + + expect(Hawk.utils.version()).to.equal(Package.version); + done(); + }); + }); + }); +}); + + diff --git a/node_modules/request/node_modules/json-stringify-safe/LICENSE b/node_modules/request/node_modules/json-stringify-safe/LICENSE new file mode 100644 index 000000000..0c44ae716 --- /dev/null +++ b/node_modules/request/node_modules/json-stringify-safe/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) Isaac Z. Schlueter ("Author") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/request/node_modules/json-stringify-safe/README.md b/node_modules/request/node_modules/json-stringify-safe/README.md new file mode 100644 index 000000000..c0537a9c3 --- /dev/null +++ b/node_modules/request/node_modules/json-stringify-safe/README.md @@ -0,0 +1,27 @@ +# json-stringify-safe + +Like JSON.stringify, but doesn't throw on circular references. + +## Usage + +Takes the same arguments as `JSON.stringify`. + +```javascript +var stringify = require('json-stringify-safe'); +var circularObj = {}; +circularObj.circularRef = circularObj; +circularObj.list = [ circularObj, circularObj ]; +console.log(stringify(circularObj, null, 2)); +``` + +Output: + +```json +{ + "circularRef": "[Circular]", + "list": [ + "[Circular]", + "[Circular]" + ] +} +``` diff --git a/node_modules/request/node_modules/json-stringify-safe/package.json b/node_modules/request/node_modules/json-stringify-safe/package.json new file mode 100644 index 000000000..7224fefaf --- /dev/null +++ b/node_modules/request/node_modules/json-stringify-safe/package.json @@ -0,0 +1,33 @@ +{ + "name": "json-stringify-safe", + "version": "3.0.0", + "description": "Like JSON.stringify, but doesn't blow up on circular refs", + "main": "stringify.js", + "scripts": { + "test": "node test.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/isaacs/json-stringify-safe" + }, + "keywords": [ + "json", + "stringify", + "circular", + "safe" + ], + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me" + }, + "license": "BSD", + "readmeFilename": "README.md", + "readme": "# json-stringify-safe\n\nLike JSON.stringify, but doesn't throw on circular references.\n\n## Usage\n\nTakes the same arguments as `JSON.stringify`.\n\n```javascript\nvar stringify = require('json-stringify-safe');\nvar circularObj = {};\ncircularObj.circularRef = circularObj;\ncircularObj.list = [ circularObj, circularObj ];\nconsole.log(stringify(circularObj, null, 2));\n```\n\nOutput:\n\n```json\n{\n \"circularRef\": \"[Circular]\",\n \"list\": [\n \"[Circular]\",\n \"[Circular]\"\n ]\n}\n```\n", + "_id": "json-stringify-safe@3.0.0", + "dist": { + "shasum": "9db7b0e530c7f289c5e8c8432af191c2ff75a5b3" + }, + "_from": "json-stringify-safe@~3.0.0", + "_resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-3.0.0.tgz" +} diff --git a/node_modules/request/node_modules/json-stringify-safe/stringify.js b/node_modules/request/node_modules/json-stringify-safe/stringify.js new file mode 100644 index 000000000..d30e21fc9 --- /dev/null +++ b/node_modules/request/node_modules/json-stringify-safe/stringify.js @@ -0,0 +1,22 @@ +module.exports = stringify; + +function getSerialize (fn) { + var seen = []; + return function(key, value) { + var ret = value; + if (typeof value === 'object' && value) { + if (seen.indexOf(value) !== -1) + ret = '[Circular]'; + else + seen.push(value); + } + if (fn) ret = fn(key, ret); + return ret; + } +} + +function stringify(obj, fn, spaces) { + return JSON.stringify(obj, getSerialize(fn), spaces); +} + +stringify.getSerialize = getSerialize; diff --git a/node_modules/request/node_modules/json-stringify-safe/test.js b/node_modules/request/node_modules/json-stringify-safe/test.js new file mode 100644 index 000000000..885e2529b --- /dev/null +++ b/node_modules/request/node_modules/json-stringify-safe/test.js @@ -0,0 +1,22 @@ +var stringify = require('./stringify.js'); + +var circularObj = {}; +circularObj.circularRef = circularObj; +circularObj.list = [ circularObj, circularObj ]; + +var testObj = { + "circularRef": "[Circular]", + "list": [ + "[Circular]", + "[Circular]" + ] +}; + +var assert = require('assert'); +assert.equal(JSON.stringify(testObj, null, 2), + stringify(circularObj, null, 2)); + +assert.equal(JSON.stringify(testObj, null, 2), + JSON.stringify(circularObj, stringify.getSerialize(), 2)); + +console.log('ok'); diff --git a/node_modules/request/node_modules/mime/LICENSE b/node_modules/request/node_modules/mime/LICENSE new file mode 100644 index 000000000..451fc4550 --- /dev/null +++ b/node_modules/request/node_modules/mime/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Benjamin Thomas, Robert Kieffer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/request/node_modules/mime/README.md b/node_modules/request/node_modules/mime/README.md new file mode 100644 index 000000000..b90552a3b --- /dev/null +++ b/node_modules/request/node_modules/mime/README.md @@ -0,0 +1,63 @@ +# mime + +Comprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community. + +## Install + +Install with [npm](http://github.com/isaacs/npm): + + npm install mime + +## API - Queries + +### mime.lookup(path) +Get the mime type associated with a file. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g. + + var mime = require('mime'); + + mime.lookup('/path/to/file.txt'); // => 'text/plain' + mime.lookup('file.txt'); // => 'text/plain' + mime.lookup('.TXT'); // => 'text/plain' + mime.lookup('htm'); // => 'text/html' + +### mime.extension(type) +Get the default extension for `type` + + mime.extension('text/html'); // => 'html' + mime.extension('application/octet-stream'); // => 'bin' + +### mime.charsets.lookup() + +Map mime-type to charset + + mime.charsets.lookup('text/plain'); // => 'UTF-8' + +(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.) + +## API - Defining Custom Types + +The following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types). + +### mime.define() + +Add custom mime/extension mappings + + mime.define({ + 'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'], + 'application/x-my-type': ['x-mt', 'x-mtt'], + // etc ... + }); + + mime.lookup('x-sft'); // => 'text/x-some-format' + +The first entry in the extensions array is returned by `mime.extension()`. E.g. + + mime.extension('text/x-some-format'); // => 'x-sf' + +### mime.load(filepath) + +Load mappings from an Apache ".types" format file + + mime.load('./my_project.types'); + +The .types file format is simple - See the `types` dir for examples. diff --git a/node_modules/request/node_modules/mime/mime.js b/node_modules/request/node_modules/mime/mime.js new file mode 100644 index 000000000..70a638424 --- /dev/null +++ b/node_modules/request/node_modules/mime/mime.js @@ -0,0 +1,113 @@ +var path = require('path'); +var fs = require('fs'); + +function Mime() { + // Map of extension -> mime type + this.types = Object.create(null); + + // Map of mime type -> extension + this.extensions = Object.create(null); +} + +/** + * Define mimetype -> extension mappings. Each key is a mime-type that maps + * to an array of extensions associated with the type. The first extension is + * used as the default extension for the type. + * + * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); + * + * @param map (Object) type definitions + */ +Mime.prototype.define = function (map) { + for (var type in map) { + var exts = map[type]; + + for (var i = 0; i < exts.length; i++) { + if (process.env.DEBUG_MIME && this.types[exts]) { + console.warn(this._loading.replace(/.*\//, ''), 'changes "' + exts[i] + '" extension type from ' + + this.types[exts] + ' to ' + type); + } + + this.types[exts[i]] = type; + } + + // Default extension is the first one we encounter + if (!this.extensions[type]) { + this.extensions[type] = exts[0]; + } + } +}; + +/** + * Load an Apache2-style ".types" file + * + * This may be called multiple times (it's expected). Where files declare + * overlapping types/extensions, the last file wins. + * + * @param file (String) path of file to load. + */ +Mime.prototype.load = function(file) { + + this._loading = file; + // Read file and split into lines + var map = {}, + content = fs.readFileSync(file, 'ascii'), + lines = content.split(/[\r\n]+/); + + lines.forEach(function(line) { + // Clean up whitespace/comments, and split into fields + var fields = line.replace(/\s*#.*|^\s*|\s*$/g, '').split(/\s+/); + map[fields.shift()] = fields; + }); + + this.define(map); + + this._loading = null; +}; + +/** + * Lookup a mime type based on extension + */ +Mime.prototype.lookup = function(path, fallback) { + var ext = path.replace(/.*[\.\/]/, '').toLowerCase(); + + return this.types[ext] || fallback || this.default_type; +}; + +/** + * Return file extension associated with a mime type + */ +Mime.prototype.extension = function(mimeType) { + return this.extensions[mimeType]; +}; + +// Default instance +var mime = new Mime(); + +// Load local copy of +// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types +mime.load(path.join(__dirname, 'types/mime.types')); + +// Load additional types from node.js community +mime.load(path.join(__dirname, 'types/node.types')); + +// Default type +mime.default_type = mime.lookup('bin'); + +// +// Additional API specific to the default instance +// + +mime.Mime = Mime; + +/** + * Lookup a charset based on mime type. + */ +mime.charsets = { + lookup: function(mimeType, fallback) { + // Assume text types are utf8 + return (/^text\//).test(mimeType) ? 'UTF-8' : fallback; + } +}; + +module.exports = mime; diff --git a/node_modules/request/node_modules/mime/package.json b/node_modules/request/node_modules/mime/package.json new file mode 100644 index 000000000..f63dcd929 --- /dev/null +++ b/node_modules/request/node_modules/mime/package.json @@ -0,0 +1,36 @@ +{ + "author": { + "name": "Robert Kieffer", + "email": "robert@broofa.com", + "url": "http://github.com/broofa" + }, + "contributors": [ + { + "name": "Benjamin Thomas", + "email": "benjamin@benjaminthomas.org", + "url": "http://github.com/bentomas" + } + ], + "dependencies": {}, + "description": "A comprehensive library for mime-type mapping", + "devDependencies": {}, + "keywords": [ + "util", + "mime" + ], + "main": "mime.js", + "name": "mime", + "repository": { + "url": "https://github.com/broofa/node-mime", + "type": "git" + }, + "version": "1.2.9", + "readme": "# mime\n\nComprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community.\n\n## Install\n\nInstall with [npm](http://github.com/isaacs/npm):\n\n npm install mime\n\n## API - Queries\n\n### mime.lookup(path)\nGet the mime type associated with a file. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g.\n\n var mime = require('mime');\n\n mime.lookup('/path/to/file.txt'); // => 'text/plain'\n mime.lookup('file.txt'); // => 'text/plain'\n mime.lookup('.TXT'); // => 'text/plain'\n mime.lookup('htm'); // => 'text/html'\n\n### mime.extension(type)\nGet the default extension for `type`\n\n mime.extension('text/html'); // => 'html'\n mime.extension('application/octet-stream'); // => 'bin'\n\n### mime.charsets.lookup()\n\nMap mime-type to charset\n\n mime.charsets.lookup('text/plain'); // => 'UTF-8'\n\n(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.)\n\n## API - Defining Custom Types\n\nThe following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types).\n\n### mime.define()\n\nAdd custom mime/extension mappings\n\n mime.define({\n 'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'],\n 'application/x-my-type': ['x-mt', 'x-mtt'],\n // etc ...\n });\n\n mime.lookup('x-sft'); // => 'text/x-some-format'\n\nThe first entry in the extensions array is returned by `mime.extension()`. E.g.\n\n mime.extension('text/x-some-format'); // => 'x-sf'\n\n### mime.load(filepath)\n\nLoad mappings from an Apache \".types\" format file\n\n mime.load('./my_project.types');\n\nThe .types file format is simple - See the `types` dir for examples.\n", + "readmeFilename": "README.md", + "_id": "mime@1.2.9", + "dist": { + "shasum": "7991c2427950d1dc2fa64cfd7d6b6326013a6156" + }, + "_from": "mime@~1.2.7", + "_resolved": "https://registry.npmjs.org/mime/-/mime-1.2.9.tgz" +} diff --git a/node_modules/request/node_modules/mime/test.js b/node_modules/request/node_modules/mime/test.js new file mode 100644 index 000000000..cbad034a1 --- /dev/null +++ b/node_modules/request/node_modules/mime/test.js @@ -0,0 +1,55 @@ +/** + * Usage: node test.js + */ + +var mime = require('./mime'); +var assert = require('assert'); + +function eq(a, b) { + console.log('Test: ' + a + ' === ' + b); + assert.strictEqual.apply(null, arguments); +} + +console.log(Object.keys(mime.extensions).length + ' types'); +console.log(Object.keys(mime.types).length + ' extensions\n'); + +// +// Test mime lookups +// + +eq('text/plain', mime.lookup('text.txt')); +eq('text/plain', mime.lookup('.text.txt')); +eq('text/plain', mime.lookup('.txt')); +eq('text/plain', mime.lookup('txt')); +eq('application/octet-stream', mime.lookup('text.nope')); +eq('fallback', mime.lookup('text.fallback', 'fallback')); +eq('application/octet-stream', mime.lookup('constructor')); +eq('text/plain', mime.lookup('TEXT.TXT')); +eq('text/event-stream', mime.lookup('text/event-stream')); +eq('application/x-web-app-manifest+json', mime.lookup('text.webapp')); + +// +// Test extensions +// + +eq('txt', mime.extension(mime.types.text)); +eq('html', mime.extension(mime.types.htm)); +eq('bin', mime.extension('application/octet-stream')); +eq(undefined, mime.extension('constructor')); + +// +// Test node types +// + +eq('application/octet-stream', mime.lookup('file.buffer')); +eq('audio/mp4', mime.lookup('file.m4a')); + +// +// Test charsets +// + +eq('UTF-8', mime.charsets.lookup('text/plain')); +eq(undefined, mime.charsets.lookup(mime.types.js)); +eq('fallback', mime.charsets.lookup('application/octet-stream', 'fallback')); + +console.log('\nOK'); diff --git a/node_modules/request/node_modules/mime/types/mime.types b/node_modules/request/node_modules/mime/types/mime.types new file mode 100644 index 000000000..b90b16587 --- /dev/null +++ b/node_modules/request/node_modules/mime/types/mime.types @@ -0,0 +1,1588 @@ +# This file maps Internet media types to unique file extension(s). +# Although created for httpd, this file is used by many software systems +# and has been placed in the public domain for unlimited redisribution. +# +# The table below contains both registered and (common) unregistered types. +# A type that has no unique extension can be ignored -- they are listed +# here to guide configurations toward known types and to make it easier to +# identify "new" types. File extensions are also commonly used to indicate +# content languages and encodings, so choose them carefully. +# +# Internet media types should be registered as described in RFC 4288. +# The registry is at <http://www.iana.org/assignments/media-types/>. +# +# MIME type (lowercased) Extensions +# ============================================ ========== +# application/1d-interleaved-parityfec +# application/3gpp-ims+xml +# application/activemessage +application/andrew-inset ez +# application/applefile +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +# application/atomicmail +application/atomsvc+xml atomsvc +# application/auth-policy+xml +# application/batch-smtp +# application/beep+xml +# application/calendar+xml +# application/cals-1840 +# application/ccmp+xml +application/ccxml+xml ccxml +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +# application/cea-2018+xml +# application/cellml+xml +# application/cfw +# application/cnrp+xml +# application/commonground +# application/conference-info+xml +# application/cpl+xml +# application/csta+xml +# application/cstadata+xml +application/cu-seeme cu +# application/cybercash +application/davmount+xml davmount +# application/dca-rft +# application/dec-dx +# application/dialog-info+xml +# application/dicom +# application/dns +application/docbook+xml dbk +# application/dskpp+xml +application/dssc+der dssc +application/dssc+xml xdssc +# application/dvcs +application/ecmascript ecma +# application/edi-consent +# application/edi-x12 +# application/edifact +application/emma+xml emma +# application/epp+xml +application/epub+zip epub +# application/eshop +# application/example +application/exi exi +# application/fastinfoset +# application/fastsoap +# application/fits +application/font-tdpfr pfr +# application/framework-attributes+xml +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +# application/h224 +# application/held+xml +# application/http +application/hyperstudio stk +# application/ibe-key-request+xml +# application/ibe-pkg-reply+xml +# application/ibe-pp-data +# application/iges +# application/im-iscomposing+xml +# application/index +# application/index.cmd +# application/index.obj +# application/index.response +# application/index.vnd +application/inkml+xml ink inkml +# application/iotp +application/ipfix ipfix +# application/ipp +# application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/jsonml+json jsonml +# application/kpml-request+xml +# application/kpml-response+xml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +# application/macwriteii +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma nb mb +# application/mathml-content+xml +# application/mathml-presentation+xml +application/mathml+xml mathml +# application/mbms-associated-procedure-description+xml +# application/mbms-deregister+xml +# application/mbms-envelope+xml +# application/mbms-msk+xml +# application/mbms-msk-response+xml +# application/mbms-protection-description+xml +# application/mbms-reception-report+xml +# application/mbms-register+xml +# application/mbms-register-response+xml +# application/mbms-user-service-description+xml +application/mbox mbox +# application/media_control+xml +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +# application/mikey +application/mods+xml mods +# application/moss-keys +# application/moss-signature +# application/mosskey-data +# application/mosskey-request +application/mp21 m21 mp21 +application/mp4 mp4s +# application/mpeg4-generic +# application/mpeg4-iod +# application/mpeg4-iod-xmt +# application/msc-ivr+xml +# application/msc-mixer+xml +application/msword doc dot +application/mxf mxf +# application/nasdata +# application/news-checkgroups +# application/news-groupinfo +# application/news-transmission +# application/nss +# application/ocsp-request +# application/ocsp-response +application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onetoc onetoc2 onetmp onepkg +application/oxps oxps +# application/parityfec +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +# application/pgp-keys +application/pgp-signature asc sig +application/pics-rules prf +# application/pidf+xml +# application/pidf-diff+xml +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +# application/poc-settings+xml +application/postscript ai eps ps +# application/prs.alvestrand.titrax-sheet +application/prs.cww cww +# application/prs.nprend +# application/prs.plucker +# application/prs.rdf-xml-crypt +# application/prs.xsf+xml +application/pskc+xml pskcxml +# application/qsig +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +# application/remote-printing +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +# application/riscos +# application/rlmi+xml +application/rls-services+xml rs +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +# application/rpki-updown +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +# application/rtx +# application/samlassertion+xml +# application/samlmetadata+xml +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +# application/set-payment +application/set-payment-initiation setpay +# application/set-registration +application/set-registration-initiation setreg +# application/sgml +# application/sgml-open-catalog +application/shf+xml shf +# application/sieve +# application/simple-filter+xml +# application/simple-message-summary +# application/simplesymbolcontainer +# application/slate +# application/smil +application/smil+xml smi smil +# application/soap+fastinfoset +# application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +# application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +# application/tamp-apex-update +# application/tamp-apex-update-confirm +# application/tamp-community-update +# application/tamp-community-update-confirm +# application/tamp-error +# application/tamp-sequence-adjust +# application/tamp-sequence-adjust-confirm +# application/tamp-status-query +# application/tamp-status-response +# application/tamp-update +# application/tamp-update-confirm +application/tei+xml tei teicorpus +application/thraud+xml tfi +# application/timestamp-query +# application/timestamp-reply +application/timestamped-data tsd +# application/tve-trigger +# application/ulpfec +# application/vcard+xml +# application/vemmi +# application/vividence.scriptfile +# application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +# application/vnd.3gpp.sms +# application/vnd.3gpp2.bcmcsinfo+xml +# application/vnd.3gpp2.sms +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +# application/vnd.adobe.partial-upload +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +# application/vnd.aether.imp +# application/vnd.ah-barcode +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +# application/vnd.amundsen.maze+xml +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.mpegurl m3u8 +# application/vnd.arastra.swi +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +# application/vnd.autopackage +# application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +# application/vnd.bluetooth.ep.oob +application/vnd.bmi bmi +application/vnd.businessobjects rep +# application/vnd.cab-jscript +# application/vnd.canon-cpdl +# application/vnd.canon-lips +# application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +# application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +# application/vnd.collection+json +# application/vnd.commerce-battelle +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +# application/vnd.ctct.ws+xml +# application/vnd.cups-pdf +# application/vnd.cups-postscript +application/vnd.cups-ppd ppd +# application/vnd.cups-raster +# application/vnd.cups-raw +# application/vnd.curl +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +# application/vnd.cybank +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvx uvvx +application/vnd.dece.zip uvz uvvz +application/vnd.denovo.fcselayout-link fe_launch +# application/vnd.dir-bi.plate-dl-nosuffix +application/vnd.dna dna +application/vnd.dolby.mlp mlp +# application/vnd.dolby.mobile.1 +# application/vnd.dolby.mobile.2 +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +# application/vnd.dvb.dvbj +# application/vnd.dvb.esgcontainer +# application/vnd.dvb.ipdcdftnotifaccess +# application/vnd.dvb.ipdcesgaccess +# application/vnd.dvb.ipdcesgaccess2 +# application/vnd.dvb.ipdcesgpdd +# application/vnd.dvb.ipdcroaming +# application/vnd.dvb.iptv.alfec-base +# application/vnd.dvb.iptv.alfec-enhancement +# application/vnd.dvb.notif-aggregate-root+xml +# application/vnd.dvb.notif-container+xml +# application/vnd.dvb.notif-generic+xml +# application/vnd.dvb.notif-ia-msglist+xml +# application/vnd.dvb.notif-ia-registration-request+xml +# application/vnd.dvb.notif-ia-registration-response+xml +# application/vnd.dvb.notif-init+xml +# application/vnd.dvb.pfr +application/vnd.dvb.service svc +# application/vnd.dxr +application/vnd.dynageo geo +# application/vnd.easykaraoke.cdgdownload +# application/vnd.ecdis-update +application/vnd.ecowin.chart mag +# application/vnd.ecowin.filerequest +# application/vnd.ecowin.fileupdate +# application/vnd.ecowin.series +# application/vnd.ecowin.seriesrequest +# application/vnd.ecowin.seriesupdate +# application/vnd.emclient.accessrequest+xml +application/vnd.enliven nml +# application/vnd.eprints.data+xml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +# application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +# application/vnd.etsi.aoc+xml +# application/vnd.etsi.cug+xml +# application/vnd.etsi.iptvcommand+xml +# application/vnd.etsi.iptvdiscovery+xml +# application/vnd.etsi.iptvprofile+xml +# application/vnd.etsi.iptvsad-bc+xml +# application/vnd.etsi.iptvsad-cod+xml +# application/vnd.etsi.iptvsad-npvr+xml +# application/vnd.etsi.iptvservice+xml +# application/vnd.etsi.iptvsync+xml +# application/vnd.etsi.iptvueprofile+xml +# application/vnd.etsi.mcid+xml +# application/vnd.etsi.overload-control-policy-dataset+xml +# application/vnd.etsi.sci+xml +# application/vnd.etsi.simservs+xml +# application/vnd.etsi.tsl+xml +# application/vnd.etsi.tsl.der +# application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +# application/vnd.f-secure.mobile +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed seed dataless +# application/vnd.ffsns +# application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +# application/vnd.font-fontforge-sfd +application/vnd.framemaker fm frame maker book +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +# application/vnd.fujixerox.art-ex +# application/vnd.fujixerox.art4 +# application/vnd.fujixerox.hbpl +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +# application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +# application/vnd.geocube+xml +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +# application/vnd.globalplatform.card-content-mgt +# application/vnd.globalplatform.card-content-mgt-response +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +# application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +# application/vnd.hal+json +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +# application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +# application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +# application/vnd.hzn-3d-crossword +# application/vnd.ibm.afplinedata +# application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +# application/vnd.informedcontrol.rms+xml +# application/vnd.informix-visionary +# application/vnd.infotech.project +# application/vnd.infotech.project+xml +# application/vnd.innopath.wamp.notification +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +# application/vnd.intertrust.digibox +# application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +# application/vnd.iptc.g2.conceptitem+xml +# application/vnd.iptc.g2.knowledgeitem+xml +# application/vnd.iptc.g2.newsitem+xml +# application/vnd.iptc.g2.newsmessage+xml +# application/vnd.iptc.g2.packageitem+xml +# application/vnd.iptc.g2.planningitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +# application/vnd.japannet-directory-service +# application/vnd.japannet-jpnstore-wakeup +# application/vnd.japannet-payment-wakeup +# application/vnd.japannet-registration +# application/vnd.japannet-registration-wakeup +# application/vnd.japannet-setstore-wakeup +# application/vnd.japannet-verification +# application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +# application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +# application/vnd.marlin.drm.actiontoken+xml +# application/vnd.marlin.drm.conftoken+xml +# application/vnd.marlin.drm.license+xml +# application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +# application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +# application/vnd.minisoft-hp3000-save +# application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +# application/vnd.motorola.flexsuite +# application/vnd.motorola.flexsuite.adsi +# application/vnd.motorola.flexsuite.fis +# application/vnd.motorola.flexsuite.gotap +# application/vnd.motorola.flexsuite.kmr +# application/vnd.motorola.flexsuite.ttc +# application/vnd.motorola.flexsuite.wem +# application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +# application/vnd.ms-asf +application/vnd.ms-cab-compressed cab +# application/vnd.ms-color.iccprofile +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +# application/vnd.ms-office.activex+xml +application/vnd.ms-officetheme thmx +# application/vnd.ms-opentype +# application/vnd.ms-package.obfuscated-opentype +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +# application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +# application/vnd.ms-printing.printticket+xml +application/vnd.ms-project mpp mpt +# application/vnd.ms-tnef +# application/vnd.ms-wmdrm.lic-chlg-req +# application/vnd.ms-wmdrm.lic-resp +# application/vnd.ms-wmdrm.meter-chlg-req +# application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +# application/vnd.msign +# application/vnd.multiad.creator +# application/vnd.multiad.creator.cif +# application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +# application/vnd.ncd.control +# application/vnd.ncd.reference +# application/vnd.nervana +# application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf ntf nitf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +# application/vnd.nokia.catalogs +# application/vnd.nokia.conml+wbxml +# application/vnd.nokia.conml+xml +# application/vnd.nokia.isds-radio-presets +# application/vnd.nokia.iptv.config+xml +# application/vnd.nokia.landmark+wbxml +# application/vnd.nokia.landmark+xml +# application/vnd.nokia.landmarkcollection+xml +# application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +# application/vnd.nokia.ncd +# application/vnd.nokia.pcd+wbxml +# application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +# application/vnd.ntt-local.file-transfer +# application/vnd.ntt-local.sip-ta_remote +# application/vnd.ntt-local.sip-ta_tcp_stream +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +# application/vnd.obn +# application/vnd.oftn.l10n+json +# application/vnd.oipf.contentaccessdownload+xml +# application/vnd.oipf.contentaccessstreaming+xml +# application/vnd.oipf.cspg-hexbinary +# application/vnd.oipf.dae.svg+xml +# application/vnd.oipf.dae.xhtml+xml +# application/vnd.oipf.mippvcontrolmessage+xml +# application/vnd.oipf.pae.gem +# application/vnd.oipf.spdiscovery+xml +# application/vnd.oipf.spdlist+xml +# application/vnd.oipf.ueprofile+xml +# application/vnd.oipf.userprofile+xml +application/vnd.olpc-sugar xo +# application/vnd.oma-scws-config +# application/vnd.oma-scws-http-request +# application/vnd.oma-scws-http-response +# application/vnd.oma.bcast.associated-procedure-parameter+xml +# application/vnd.oma.bcast.drm-trigger+xml +# application/vnd.oma.bcast.imd+xml +# application/vnd.oma.bcast.ltkm +# application/vnd.oma.bcast.notification+xml +# application/vnd.oma.bcast.provisioningtrigger +# application/vnd.oma.bcast.sgboot +# application/vnd.oma.bcast.sgdd+xml +# application/vnd.oma.bcast.sgdu +# application/vnd.oma.bcast.simple-symbol-container +# application/vnd.oma.bcast.smartcard-trigger+xml +# application/vnd.oma.bcast.sprov+xml +# application/vnd.oma.bcast.stkm +# application/vnd.oma.cab-address-book+xml +# application/vnd.oma.cab-feature-handler+xml +# application/vnd.oma.cab-pcc+xml +# application/vnd.oma.cab-user-prefs+xml +# application/vnd.oma.dcd +# application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +# application/vnd.oma.drm.risd+xml +# application/vnd.oma.group-usage-list+xml +# application/vnd.oma.pal+xml +# application/vnd.oma.poc.detailed-progress-report+xml +# application/vnd.oma.poc.final-report+xml +# application/vnd.oma.poc.groups+xml +# application/vnd.oma.poc.invocation-descriptor+xml +# application/vnd.oma.poc.optimized-progress-report+xml +# application/vnd.oma.push +# application/vnd.oma.scidm.messages+xml +# application/vnd.oma.xcap-directory+xml +# application/vnd.omads-email+xml +# application/vnd.omads-file+xml +# application/vnd.omads-folder+xml +# application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +# application/vnd.openxmlformats-officedocument.custom-properties+xml +# application/vnd.openxmlformats-officedocument.customxmlproperties+xml +# application/vnd.openxmlformats-officedocument.drawing+xml +# application/vnd.openxmlformats-officedocument.drawingml.chart+xml +# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml +# application/vnd.openxmlformats-officedocument.extended-properties+xml +# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml +# application/vnd.openxmlformats-officedocument.presentationml.comments+xml +# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +# application/vnd.openxmlformats-officedocument.presentationml.slide+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml +# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml +# application/vnd.openxmlformats-officedocument.presentationml.tags+xml +application/vnd.openxmlformats-officedocument.presentationml.template potx +# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml +# application/vnd.openxmlformats-officedocument.theme+xml +# application/vnd.openxmlformats-officedocument.themeoverride+xml +# application/vnd.openxmlformats-officedocument.vmldrawing +# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml +# application/vnd.openxmlformats-package.core-properties+xml +# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml +# application/vnd.openxmlformats-package.relationships+xml +# application/vnd.quobject-quoxdocument +# application/vnd.osa.netdeploy +application/vnd.osgeo.mapguide.package mgp +# application/vnd.osgi.bundle +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +# application/vnd.otps.ct-kip+xml +application/vnd.palm pdb pqa oprc +# application/vnd.paos.xml +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +# application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.pmi.widget wg +# application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +# application/vnd.powerbuilder6-s +# application/vnd.powerbuilder7 +# application/vnd.powerbuilder7-s +# application/vnd.powerbuilder75 +# application/vnd.powerbuilder75-s +# application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +# application/vnd.pwg-multiplexed +# application/vnd.pwg-xhtml-print+xml +# application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +# application/vnd.radisys.moml+xml +# application/vnd.radisys.msml+xml +# application/vnd.radisys.msml-audit+xml +# application/vnd.radisys.msml-audit-conf+xml +# application/vnd.radisys.msml-audit-conn+xml +# application/vnd.radisys.msml-audit-dialog+xml +# application/vnd.radisys.msml-audit-stream+xml +# application/vnd.radisys.msml-conf+xml +# application/vnd.radisys.msml-dialog+xml +# application/vnd.radisys.msml-dialog-base+xml +# application/vnd.radisys.msml-dialog-fax-detect+xml +# application/vnd.radisys.msml-dialog-fax-sendrecv+xml +# application/vnd.radisys.msml-dialog-group+xml +# application/vnd.radisys.msml-dialog-speech+xml +# application/vnd.radisys.msml-dialog-transform+xml +# application/vnd.rainstor.data +# application/vnd.rapid +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +# application/vnd.renlearn.rlprint +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +# application/vnd.rs-274x +# application/vnd.ruckus.download +# application/vnd.s3sms +application/vnd.sailingtracker.track st +# application/vnd.sbm.cid +# application/vnd.sbm.mid2 +# application/vnd.scribus +# application/vnd.sealed.3df +# application/vnd.sealed.csf +# application/vnd.sealed.doc +# application/vnd.sealed.eml +# application/vnd.sealed.mht +# application/vnd.sealed.net +# application/vnd.sealed.ppt +# application/vnd.sealed.tiff +# application/vnd.sealed.xls +# application/vnd.sealedmedia.softseal.html +# application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +# application/vnd.smart.notebook +application/vnd.smart.teacher teacher +# application/vnd.software602.filler.form+xml +# application/vnd.software602.filler.form-xml-zip +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +# application/vnd.sss-cod +# application/vnd.sss-dtf +# application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +# application/vnd.street-stream +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +# application/vnd.sun.wadl+xml +application/vnd.sus-calendar sus susp +application/vnd.svd svd +# application/vnd.swiftview-ics +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +# application/vnd.syncml.dm.notification +# application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap pcap cap dmp +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +# application/vnd.truedoc +# application/vnd.ubisoft.webplayer +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +# application/vnd.uplanet.alert +# application/vnd.uplanet.alert-wbxml +# application/vnd.uplanet.bearer-choice +# application/vnd.uplanet.bearer-choice-wbxml +# application/vnd.uplanet.cacheop +# application/vnd.uplanet.cacheop-wbxml +# application/vnd.uplanet.channel +# application/vnd.uplanet.channel-wbxml +# application/vnd.uplanet.list +# application/vnd.uplanet.list-wbxml +# application/vnd.uplanet.listcmd +# application/vnd.uplanet.listcmd-wbxml +# application/vnd.uplanet.signal +application/vnd.vcx vcx +# application/vnd.vd-study +# application/vnd.vectorworks +# application/vnd.verimatrix.vcas +# application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +# application/vnd.vividence.scriptfile +application/vnd.vsf vsf +# application/vnd.wap.sic +# application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +# application/vnd.wfa.wsc +# application/vnd.wmc +# application/vnd.wmf.bootstrap +# application/vnd.wolfram.mathematica +# application/vnd.wolfram.mathematica.package +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +# application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +# application/vnd.wv.csp+wbxml +# application/vnd.wv.csp+xml +# application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +# application/vnd.xfdl.webform +# application/vnd.xmi+xml +# application/vnd.xmpie.cpkg +# application/vnd.xmpie.dpkg +# application/vnd.xmpie.plan +# application/vnd.xmpie.ppkg +# application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +# application/vnd.yamaha.remote-setup +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +# application/vnd.yamaha.through-ngn +# application/vnd.yamaha.tunnel-udpencap +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +# application/vq-rtcpxr +# application/watcherinfo+xml +# application/whoispp-query +# application/whoispp-response +application/widget wgt +application/winhlp hlp +# application/wita +# application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +# application/x-amf +application/x-apple-diskimage dmg +application/x-authorware-bin aab x32 u32 vox +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb blorb +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cbr cbr cba cbt cbz cb7 +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-conference nsc +# application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-dgc-compressed dgc +application/x-director dir dcr dxr cst cct cxt w3d fgd swa +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +# application/x-font-dos +# application/x-font-framemaker +application/x-font-ghostscript gsf +# application/x-font-libgrx +application/x-font-linux-psf psf +application/x-font-otf otf +application/x-font-pcf pcf +application/x-font-snf snf +# application/x-font-speedo +# application/x-font-sunos-news +application/x-font-ttf ttf ttc +application/x-font-type1 pfa pfb pfm afm +application/x-font-woff woff +# application/x-font-vfont +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +# application/x-gzip +application/x-hdf hdf +application/x-install-instructions install +application/x-iso9660-image iso +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-lzh-compressed lzh lha +application/x-mie mie +application/x-mobipocket-ebook prc mobi +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf wmz emf emz +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-nzb nzb +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-research-info-systems ris +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo texi +application/x-tgif obj +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 +# application/x400-bp +application/xaml+xml xaml +# application/xcap-att+xml +# application/xcap-caps+xml +application/xcap-diff+xml xdf +# application/xcap-el+xml +# application/xcap-error+xml +# application/xcap-ns+xml +# application/xcon-conference-info-diff+xml +# application/xcon-conference-info+xml +application/xenc+xml xenc +application/xhtml+xml xhtml xht +# application/xhtml-voice+xml +application/xml xml xsl +application/xml-dtd dtd +# application/xml-external-parsed-entity +# application/xmpp+xml +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/yang yang +application/yin+xml yin +application/zip zip +# audio/1d-interleaved-parityfec +# audio/32kadpcm +# audio/3gpp +# audio/3gpp2 +# audio/ac3 +audio/adpcm adp +# audio/amr +# audio/amr-wb +# audio/amr-wb+ +# audio/asc +# audio/atrac-advanced-lossless +# audio/atrac-x +# audio/atrac3 +audio/basic au snd +# audio/bv16 +# audio/bv32 +# audio/clearmode +# audio/cn +# audio/dat12 +# audio/dls +# audio/dsr-es201108 +# audio/dsr-es202050 +# audio/dsr-es202211 +# audio/dsr-es202212 +# audio/dv +# audio/dvi4 +# audio/eac3 +# audio/evrc +# audio/evrc-qcp +# audio/evrc0 +# audio/evrc1 +# audio/evrcb +# audio/evrcb0 +# audio/evrcb1 +# audio/evrcwb +# audio/evrcwb0 +# audio/evrcwb1 +# audio/example +# audio/fwdred +# audio/g719 +# audio/g722 +# audio/g7221 +# audio/g723 +# audio/g726-16 +# audio/g726-24 +# audio/g726-32 +# audio/g726-40 +# audio/g728 +# audio/g729 +# audio/g7291 +# audio/g729d +# audio/g729e +# audio/gsm +# audio/gsm-efr +# audio/gsm-hr-08 +# audio/ilbc +# audio/ip-mr_v2.5 +# audio/isac +# audio/l16 +# audio/l20 +# audio/l24 +# audio/l8 +# audio/lpc +audio/midi mid midi kar rmi +# audio/mobile-xmf +audio/mp4 mp4a +# audio/mp4a-latm +# audio/mpa +# audio/mpa-robust +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +# audio/mpeg4-generic +# audio/musepack +audio/ogg oga ogg spx +# audio/opus +# audio/parityfec +# audio/pcma +# audio/pcma-wb +# audio/pcmu-wb +# audio/pcmu +# audio/prs.sid +# audio/qcelp +# audio/red +# audio/rtp-enc-aescm128 +# audio/rtp-midi +# audio/rtx +audio/s3m s3m +audio/silk sil +# audio/smv +# audio/smv0 +# audio/smv-qcp +# audio/sp-midi +# audio/speex +# audio/t140c +# audio/t38 +# audio/telephone-event +# audio/tone +# audio/uemclip +# audio/ulpfec +# audio/vdvi +# audio/vmr-wb +# audio/vnd.3gpp.iufp +# audio/vnd.4sb +# audio/vnd.audiokoz +# audio/vnd.celp +# audio/vnd.cisco.nse +# audio/vnd.cmles.radio-events +# audio/vnd.cns.anp1 +# audio/vnd.cns.inf1 +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +# audio/vnd.dlna.adts +# audio/vnd.dolby.heaac.1 +# audio/vnd.dolby.heaac.2 +# audio/vnd.dolby.mlp +# audio/vnd.dolby.mps +# audio/vnd.dolby.pl2 +# audio/vnd.dolby.pl2x +# audio/vnd.dolby.pl2z +# audio/vnd.dolby.pulse.1 +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +# audio/vnd.dvb.file +# audio/vnd.everad.plj +# audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +# audio/vnd.nokia.mobile-xmf +# audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +# audio/vnd.octel.sbc +# audio/vnd.qcelp +# audio/vnd.rhetorex.32kadpcm +audio/vnd.rip rip +# audio/vnd.sealedmedia.softseal.mpeg +# audio/vnd.vmx.cvsd +# audio/vorbis +# audio/vorbis-config +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aiff aifc +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +# audio/x-tta +audio/x-wav wav +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +# chemical/x-pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +# image/example +# image/fits +image/g3fax g3 +image/gif gif +image/ief ief +# image/jp2 +image/jpeg jpeg jpg jpe +# image/jpm +# image/jpx +image/ktx ktx +# image/naplps +image/png png +image/prs.btif btif +# image/prs.pti +image/sgi sgi +image/svg+xml svg svgz +# image/t38 +image/tiff tiff tif +# image/tiff-fx +image/vnd.adobe.photoshop psd +# image/vnd.cns.inf2 +image/vnd.dece.graphic uvi uvvi uvg uvvg +image/vnd.dvb.subtitle sub +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +# image/vnd.globalgraphics.pgb +# image/vnd.microsoft.icon +# image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +# image/vnd.radiance +# image/vnd.sealed.png +# image/vnd.sealedmedia.softseal.gif +# image/vnd.sealedmedia.softseal.jpg +# image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fhc fh4 fh5 fh7 +image/x-icon ico +image/x-mrsid-image sid +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +# message/cpim +# message/delivery-status +# message/disposition-notification +# message/example +# message/external-body +# message/feedback-report +# message/global +# message/global-delivery-status +# message/global-disposition-notification +# message/global-headers +# message/http +# message/imdn+xml +# message/news +# message/partial +message/rfc822 eml mime +# message/s-http +# message/sip +# message/sipfrag +# message/tracking-status +# message/vnd.si.simp +# model/example +model/iges igs iges +model/mesh msh mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +# model/vnd.flatland.3dml +model/vnd.gdl gdl +# model/vnd.gs-gdl +# model/vnd.gs.gdl +model/vnd.gtw gtw +# model/vnd.moml+xml +model/vnd.mts mts +# model/vnd.parasolid.transmit.binary +# model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml wrl vrml +model/x3d+binary x3db x3dbz +model/x3d+vrml x3dv x3dvz +model/x3d+xml x3d x3dz +# multipart/alternative +# multipart/appledouble +# multipart/byteranges +# multipart/digest +# multipart/encrypted +# multipart/example +# multipart/form-data +# multipart/header-set +# multipart/mixed +# multipart/parallel +# multipart/related +# multipart/report +# multipart/signed +# multipart/voice-message +# text/1d-interleaved-parityfec +text/cache-manifest appcache +text/calendar ics ifb +text/css css +text/csv csv +# text/directory +# text/dns +# text/ecmascript +# text/enriched +# text/example +# text/fwdred +text/html html htm +# text/javascript +text/n3 n3 +# text/parityfec +text/plain txt text conf def list log in +# text/prs.fallenstein.rst +text/prs.lines.tag dsc +# text/vnd.radisys.msml-basic-layout +# text/red +# text/rfc822-headers +text/richtext rtx +# text/rtf +# text/rtp-enc-aescm128 +# text/rtx +text/sgml sgml sgm +# text/t140 +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/turtle ttl +# text/ulpfec +text/uri-list uri uris urls +text/vcard vcard +# text/vnd.abc +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.scurl scurl +text/vnd.curl.mcurl mcurl +# text/vnd.dmclientscript +text/vnd.dvb.subtitle sub +# text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +# text/vnd.iptc.newsml +# text/vnd.iptc.nitf +# text/vnd.latex-z +# text/vnd.motorola.reflex +# text/vnd.ms-mediapackage +# text/vnd.net2phone.commcenter.command +# text/vnd.si.uricatalogue +text/vnd.sun.j2me.app-descriptor jad +# text/vnd.trolltech.linguist +# text/vnd.wap.si +# text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-java-source java +text/x-opml opml +text/x-pascal p pas +text/x-nfo nfo +text/x-setext etx +text/x-sfv sfv +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +# text/xml +# text/xml-external-parsed-entity +# video/1d-interleaved-parityfec +video/3gpp 3gp +# video/3gpp-tt +video/3gpp2 3g2 +# video/bmpeg +# video/bt656 +# video/celb +# video/dv +# video/example +video/h261 h261 +video/h263 h263 +# video/h263-1998 +# video/h263-2000 +video/h264 h264 +# video/h264-rcdo +# video/h264-svc +video/jpeg jpgv +# video/jpeg2000 +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +# video/mp1s +# video/mp2p +# video/mp2t +video/mp4 mp4 mp4v mpg4 +# video/mp4v-es +video/mpeg mpeg mpg mpe m1v m2v +# video/mpeg4-generic +# video/mpv +# video/nv +video/ogg ogv +# video/parityfec +# video/pointer +video/quicktime qt mov +# video/raw +# video/rtp-enc-aescm128 +# video/rtx +# video/smpte292m +# video/ulpfec +# video/vc1 +# video/vnd.cctv +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +# video/vnd.dece.mp4 +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +# video/vnd.directv.mpeg +# video/vnd.directv.mpeg-tts +# video/vnd.dlna.mpeg-tts +video/vnd.dvb.file dvb +video/vnd.fvt fvt +# video/vnd.hns.video +# video/vnd.iptvforum.1dparityfec-1010 +# video/vnd.iptvforum.1dparityfec-2005 +# video/vnd.iptvforum.2dparityfec-1010 +# video/vnd.iptvforum.2dparityfec-2005 +# video/vnd.iptvforum.ttsavc +# video/vnd.iptvforum.ttsmpeg2 +# video/vnd.motorola.video +# video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +# video/vnd.nokia.interleaved-multimedia +# video/vnd.nokia.videovoip +# video/vnd.objectvideo +# video/vnd.sealed.mpeg1 +# video/vnd.sealed.mpeg4 +# video/vnd.sealed.swf +# video/vnd.sealedmedia.softseal.mov +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mkv mk3d mks +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice diff --git a/node_modules/request/node_modules/mime/types/node.types b/node_modules/request/node_modules/mime/types/node.types new file mode 100644 index 000000000..970a1bd85 --- /dev/null +++ b/node_modules/request/node_modules/mime/types/node.types @@ -0,0 +1,60 @@ +# What: WebVTT +# Why: To allow formats intended for marking up external text track resources. +# http://dev.w3.org/html5/webvtt/ +# Added by: niftylettuce +text/vtt vtt + +# What: Google Chrome Extension +# Why: To allow apps to (work) be served with the right content type header. +# http://codereview.chromium.org/2830017 +# Added by: niftylettuce +application/x-chrome-extension crx + +# What: HTC support +# Why: To properly render .htc files such as CSS3PIE +# Added by: niftylettuce +text/x-component htc + +# What: HTML5 application cache manifest +# Why: De-facto standard. Required by Mozilla browser when serving HTML5 apps +# per https://developer.mozilla.org/en/offline_resources_in_firefox +# Added by: louisremi +text/cache-manifest appcache manifest + +# What: node binary buffer format +# Why: semi-standard extension w/in the node community +# Added by: tootallnate +application/octet-stream buffer + +# What: The "protected" MP-4 formats used by iTunes. +# Why: Required for streaming music to browsers (?) +# Added by: broofa +application/mp4 m4p +audio/mp4 m4a + +# What: Video format, Part of RFC1890 +# Why: See https://github.com/bentomas/node-mime/pull/6 +# Added by: mjrusso +video/MP2T ts + +# What: EventSource mime type +# Why: mime type of Server-Sent Events stream +# http://www.w3.org/TR/eventsource/#text-event-stream +# Added by: francois2metz +text/event-stream event-stream + +# What: Mozilla App manifest mime type +# Why: https://developer.mozilla.org/en/Apps/Manifest#Serving_manifests +# Added by: ednapiranha +application/x-web-app-manifest+json webapp + +# What: Lua file types +# Why: Googling around shows de-facto consensus on these +# Added by: creationix (Issue #45) +text/x-lua lua +application/x-lua-bytecode luac + +# What: Markdown files, as per http://daringfireball.net/projects/markdown/syntax +# Why: http://stackoverflow.com/questions/10701983/what-is-the-mime-type-for-markdown +# Added by: avoidwork +text/x-markdown markdown md mkd diff --git a/node_modules/request/node_modules/node-uuid/.npmignore b/node_modules/request/node_modules/node-uuid/.npmignore new file mode 100644 index 000000000..fd4f2b066 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/.npmignore @@ -0,0 +1,2 @@ +node_modules +.DS_Store diff --git a/node_modules/request/node_modules/node-uuid/LICENSE.md b/node_modules/request/node_modules/node-uuid/LICENSE.md new file mode 100644 index 000000000..bcdddf9a0 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/LICENSE.md @@ -0,0 +1,3 @@ +Copyright (c) 2010 Robert Kieffer + +Dual licensed under the [MIT](http://en.wikipedia.org/wiki/MIT_License) and [GPL](http://en.wikipedia.org/wiki/GNU_General_Public_License) licenses. diff --git a/node_modules/request/node_modules/node-uuid/README.md b/node_modules/request/node_modules/node-uuid/README.md new file mode 100644 index 000000000..d62f7a14d --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/README.md @@ -0,0 +1,203 @@ +# node-uuid + +Simple, fast generation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDS. + +Features: + +* Generate RFC4122 version 1 or version 4 UUIDs +* Runs in node.js and all browsers. +* Cryptographically strong random # generation on supporting platforms +* 1.1K minified and gzip'ed (Want something smaller? Check this [crazy shit](https://gist.github.com/982883) out! ) +* [Annotated source code](http://broofa.github.com/node-uuid/docs/uuid.html) + +## Getting Started + +Install it in your browser: + +```html +<script src="uuid.js"></script> +``` + +Or in node.js: + +``` +npm install node-uuid +``` + +```javascript +var uuid = require('node-uuid'); +``` + +Then create some ids ... + +```javascript +// Generate a v1 (time-based) id +uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a' + +// Generate a v4 (random) id +uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1' +``` + +## API + +### uuid.v1([`options` [, `buffer` [, `offset`]]]) + +Generate and return a RFC4122 v1 (timestamp-based) UUID. + +* `options` - (Object) Optional uuid state to apply. Properties may include: + + * `node` - (Array) Node id as Array of 6 bytes (per 4.1.6). Default: Randomly generated ID. See note 1. + * `clockseq` - (Number between 0 - 0x3fff) RFC clock sequence. Default: An internally maintained clockseq is used. + * `msecs` - (Number | Date) Time in milliseconds since unix Epoch. Default: The current time is used. + * `nsecs` - (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if `msecs` is unspecified. Default: internal uuid counter is used, as per 4.2.1.2. + +* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. +* `offset` - (Number) Starting index in `buffer` at which to begin writing. + +Returns `buffer`, if specified, otherwise the string form of the UUID + +Notes: + +1. The randomly generated node id is only guaranteed to stay constant for the lifetime of the current JS runtime. (Future versions of this module may use persistent storage mechanisms to extend this guarantee.) + +Example: Generate string UUID with fully-specified options + +```javascript +uuid.v1({ + node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], + clockseq: 0x1234, + msecs: new Date('2011-11-01').getTime(), + nsecs: 5678 +}); // -> "710b962e-041c-11e1-9234-0123456789ab" +``` + +Example: In-place generation of two binary IDs + +```javascript +// Generate two ids in an array +var arr = new Array(32); // -> [] +uuid.v1(null, arr, 0); // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15] +uuid.v1(null, arr, 16); // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15 02 a3 1c b0 14 32 11 e1 85 58 0b 48 8e 4f c1 15] + +// Optionally use uuid.unparse() to get stringify the ids +uuid.unparse(buffer); // -> '02a2ce90-1432-11e1-8558-0b488e4fc115' +uuid.unparse(buffer, 16) // -> '02a31cb0-1432-11e1-8558-0b488e4fc115' +``` + +### uuid.v4([`options` [, `buffer` [, `offset`]]]) + +Generate and return a RFC4122 v4 UUID. + +* `options` - (Object) Optional uuid state to apply. Properties may include: + + * `random` - (Number[16]) Array of 16 numbers (0-255) to use in place of randomly generated values + * `rng` - (Function) Random # generator to use. Set to one of the built-in generators - `uuid.mathRNG` (all platforms), `uuid.nodeRNG` (node.js only), `uuid.whatwgRNG` (WebKit only) - or a custom function that returns an array[16] of byte values. + +* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. +* `offset` - (Number) Starting index in `buffer` at which to begin writing. + +Returns `buffer`, if specified, otherwise the string form of the UUID + +Example: Generate string UUID with fully-specified options + +```javascript +uuid.v4({ + random: [ + 0x10, 0x91, 0x56, 0xbe, 0xc4, 0xfb, 0xc1, 0xea, + 0x71, 0xb4, 0xef, 0xe1, 0x67, 0x1c, 0x58, 0x36 + ] +}); +// -> "109156be-c4fb-41ea-b1b4-efe1671c5836" +``` + +Example: Generate two IDs in a single buffer + +```javascript +var buffer = new Array(32); // (or 'new Buffer' in node.js) +uuid.v4(null, buffer, 0); +uuid.v4(null, buffer, 16); +``` + +### uuid.parse(id[, buffer[, offset]]) +### uuid.unparse(buffer[, offset]) + +Parse and unparse UUIDs + + * `id` - (String) UUID(-like) string + * `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. Default: A new Array or Buffer is used + * `offset` - (Number) Starting index in `buffer` at which to begin writing. Default: 0 + +Example parsing and unparsing a UUID string + +```javascript +var bytes = uuid.parse('797ff043-11eb-11e1-80d6-510998755d10'); // -> <Buffer 79 7f f0 43 11 eb 11 e1 80 d6 51 09 98 75 5d 10> +var string = uuid.unparse(bytes); // -> '797ff043-11eb-11e1-80d6-510998755d10' +``` + +### uuid.noConflict() + +(Browsers only) Set `uuid` property back to it's previous value. + +Returns the node-uuid object. + +Example: + +```javascript +var myUuid = uuid.noConflict(); +myUuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a' +``` + +## Deprecated APIs + +Support for the following v1.2 APIs is available in v1.3, but is deprecated and will be removed in the next major version. + +### uuid([format [, buffer [, offset]]]) + +uuid() has become uuid.v4(), and the `format` argument is now implicit in the `buffer` argument. (i.e. if you specify a buffer, the format is assumed to be binary). + +### uuid.BufferClass + +The class of container created when generating binary uuid data if no buffer argument is specified. This is expected to go away, with no replacement API. + +## Testing + +In node.js + +``` +> cd test +> node test.js +``` + +In Browser + +``` +open test/test.html +``` + +### Benchmarking + +Requires node.js + +``` +npm install uuid uuid-js +node benchmark/benchmark.js +``` + +For a more complete discussion of node-uuid performance, please see the `benchmark/README.md` file, and the [benchmark wiki](https://github.com/broofa/node-uuid/wiki/Benchmark) + +For browser performance [checkout the JSPerf tests](http://jsperf.com/node-uuid-performance). + +## Release notes + +v1.4 +* Improved module context detection +* Removed public RNG functions + +v1.3.2: +* Improve tests and handling of v1() options (Issue #24) +* Expose RNG option to allow for perf testing with different generators + +v1.3: +* Support for version 1 ids, thanks to [@ctavan](https://github.com/ctavan)! +* Support for node.js crypto API +* De-emphasizing performance in favor of a) cryptographic quality PRNGs where available and b) more manageable code diff --git a/node_modules/request/node_modules/node-uuid/benchmark/README.md b/node_modules/request/node_modules/node-uuid/benchmark/README.md new file mode 100644 index 000000000..aaeb2ea01 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/benchmark/README.md @@ -0,0 +1,53 @@ +# node-uuid Benchmarks + +### Results + +To see the results of our benchmarks visit https://github.com/broofa/node-uuid/wiki/Benchmark + +### Run them yourself + +node-uuid comes with some benchmarks to measure performance of generating UUIDs. These can be run using node.js. node-uuid is being benchmarked against some other uuid modules, that are available through npm namely `uuid` and `uuid-js`. + +To prepare and run the benchmark issue; + +``` +npm install uuid uuid-js +node benchmark/benchmark.js +``` + +You'll see an output like this one: + +``` +# v4 +nodeuuid.v4(): 854700 uuids/second +nodeuuid.v4('binary'): 788643 uuids/second +nodeuuid.v4('binary', buffer): 1336898 uuids/second +uuid(): 479386 uuids/second +uuid('binary'): 582072 uuids/second +uuidjs.create(4): 312304 uuids/second + +# v1 +nodeuuid.v1(): 938086 uuids/second +nodeuuid.v1('binary'): 683060 uuids/second +nodeuuid.v1('binary', buffer): 1644736 uuids/second +uuidjs.create(1): 190621 uuids/second +``` + +* The `uuid()` entries are for Nikhil Marathe's [uuid module](https://bitbucket.org/nikhilm/uuidjs) which is a wrapper around the native libuuid library. +* The `uuidjs()` entries are for Patrick Negri's [uuid-js module](https://github.com/pnegri/uuid-js) which is a pure javascript implementation based on [UUID.js](https://github.com/LiosK/UUID.js) by LiosK. + +If you want to get more reliable results you can run the benchmark multiple times and write the output into a log file: + +``` +for i in {0..9}; do node benchmark/benchmark.js >> benchmark/bench_0.4.12.log; done; +``` + +If you're interested in how performance varies between different node versions, you can issue the above command multiple times. + +You can then use the shell script `bench.sh` provided in this directory to calculate the averages over all benchmark runs and draw a nice plot: + +``` +(cd benchmark/ && ./bench.sh) +``` + +This assumes you have [gnuplot](http://www.gnuplot.info/) and [ImageMagick](http://www.imagemagick.org/) installed. You'll find a nice `bench.png` graph in the `benchmark/` directory then. diff --git a/node_modules/request/node_modules/node-uuid/benchmark/bench.gnu b/node_modules/request/node_modules/node-uuid/benchmark/bench.gnu new file mode 100644 index 000000000..a342fbbe0 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/benchmark/bench.gnu @@ -0,0 +1,174 @@ +#!/opt/local/bin/gnuplot -persist +# +# +# G N U P L O T +# Version 4.4 patchlevel 3 +# last modified March 2011 +# System: Darwin 10.8.0 +# +# Copyright (C) 1986-1993, 1998, 2004, 2007-2010 +# Thomas Williams, Colin Kelley and many others +# +# gnuplot home: http://www.gnuplot.info +# faq, bugs, etc: type "help seeking-assistance" +# immediate help: type "help" +# plot window: hit 'h' +set terminal postscript eps noenhanced defaultplex \ + leveldefault color colortext \ + solid linewidth 1.2 butt noclip \ + palfuncparam 2000,0.003 \ + "Helvetica" 14 +set output 'bench.eps' +unset clip points +set clip one +unset clip two +set bar 1.000000 front +set border 31 front linetype -1 linewidth 1.000 +set xdata +set ydata +set zdata +set x2data +set y2data +set timefmt x "%d/%m/%y,%H:%M" +set timefmt y "%d/%m/%y,%H:%M" +set timefmt z "%d/%m/%y,%H:%M" +set timefmt x2 "%d/%m/%y,%H:%M" +set timefmt y2 "%d/%m/%y,%H:%M" +set timefmt cb "%d/%m/%y,%H:%M" +set boxwidth +set style fill empty border +set style rectangle back fc lt -3 fillstyle solid 1.00 border lt -1 +set style circle radius graph 0.02, first 0, 0 +set dummy x,y +set format x "% g" +set format y "% g" +set format x2 "% g" +set format y2 "% g" +set format z "% g" +set format cb "% g" +set angles radians +unset grid +set key title "" +set key outside left top horizontal Right noreverse enhanced autotitles columnhead nobox +set key noinvert samplen 4 spacing 1 width 0 height 0 +set key maxcolumns 2 maxrows 0 +unset label +unset arrow +set style increment default +unset style line +set style line 1 linetype 1 linewidth 2.000 pointtype 1 pointsize default pointinterval 0 +unset style arrow +set style histogram clustered gap 2 title offset character 0, 0, 0 +unset logscale +set offsets graph 0.05, 0.15, 0, 0 +set pointsize 1.5 +set pointintervalbox 1 +set encoding default +unset polar +unset parametric +unset decimalsign +set view 60, 30, 1, 1 +set samples 100, 100 +set isosamples 10, 10 +set surface +unset contour +set clabel '%8.3g' +set mapping cartesian +set datafile separator whitespace +unset hidden3d +set cntrparam order 4 +set cntrparam linear +set cntrparam levels auto 5 +set cntrparam points 5 +set size ratio 0 1,1 +set origin 0,0 +set style data points +set style function lines +set xzeroaxis linetype -2 linewidth 1.000 +set yzeroaxis linetype -2 linewidth 1.000 +set zzeroaxis linetype -2 linewidth 1.000 +set x2zeroaxis linetype -2 linewidth 1.000 +set y2zeroaxis linetype -2 linewidth 1.000 +set ticslevel 0.5 +set mxtics default +set mytics default +set mztics default +set mx2tics default +set my2tics default +set mcbtics default +set xtics border in scale 1,0.5 mirror norotate offset character 0, 0, 0 +set xtics norangelimit +set xtics () +set ytics border in scale 1,0.5 mirror norotate offset character 0, 0, 0 +set ytics autofreq norangelimit +set ztics border in scale 1,0.5 nomirror norotate offset character 0, 0, 0 +set ztics autofreq norangelimit +set nox2tics +set noy2tics +set cbtics border in scale 1,0.5 mirror norotate offset character 0, 0, 0 +set cbtics autofreq norangelimit +set title "" +set title offset character 0, 0, 0 font "" norotate +set timestamp bottom +set timestamp "" +set timestamp offset character 0, 0, 0 font "" norotate +set rrange [ * : * ] noreverse nowriteback # (currently [8.98847e+307:-8.98847e+307] ) +set autoscale rfixmin +set autoscale rfixmax +set trange [ * : * ] noreverse nowriteback # (currently [-5.00000:5.00000] ) +set autoscale tfixmin +set autoscale tfixmax +set urange [ * : * ] noreverse nowriteback # (currently [-10.0000:10.0000] ) +set autoscale ufixmin +set autoscale ufixmax +set vrange [ * : * ] noreverse nowriteback # (currently [-10.0000:10.0000] ) +set autoscale vfixmin +set autoscale vfixmax +set xlabel "" +set xlabel offset character 0, 0, 0 font "" textcolor lt -1 norotate +set x2label "" +set x2label offset character 0, 0, 0 font "" textcolor lt -1 norotate +set xrange [ * : * ] noreverse nowriteback # (currently [-0.150000:3.15000] ) +set autoscale xfixmin +set autoscale xfixmax +set x2range [ * : * ] noreverse nowriteback # (currently [0.00000:3.00000] ) +set autoscale x2fixmin +set autoscale x2fixmax +set ylabel "" +set ylabel offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270 +set y2label "" +set y2label offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270 +set yrange [ 0.00000 : 1.90000e+06 ] noreverse nowriteback # (currently [:] ) +set autoscale yfixmin +set autoscale yfixmax +set y2range [ * : * ] noreverse nowriteback # (currently [0.00000:1.90000e+06] ) +set autoscale y2fixmin +set autoscale y2fixmax +set zlabel "" +set zlabel offset character 0, 0, 0 font "" textcolor lt -1 norotate +set zrange [ * : * ] noreverse nowriteback # (currently [-10.0000:10.0000] ) +set autoscale zfixmin +set autoscale zfixmax +set cblabel "" +set cblabel offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270 +set cbrange [ * : * ] noreverse nowriteback # (currently [8.98847e+307:-8.98847e+307] ) +set autoscale cbfixmin +set autoscale cbfixmax +set zero 1e-08 +set lmargin -1 +set bmargin -1 +set rmargin -1 +set tmargin -1 +set pm3d explicit at s +set pm3d scansautomatic +set pm3d interpolate 1,1 flush begin noftriangles nohidden3d corners2color mean +set palette positive nops_allcF maxcolors 0 gamma 1.5 color model RGB +set palette rgbformulae 7, 5, 15 +set colorbox default +set colorbox vertical origin screen 0.9, 0.2, 0 size screen 0.05, 0.6, 0 front bdefault +set loadpath +set fontpath +set fit noerrorvariables +GNUTERM = "aqua" +plot 'bench_results.txt' using 2:xticlabel(1) w lp lw 2, '' using 3:xticlabel(1) w lp lw 2, '' using 4:xticlabel(1) w lp lw 2, '' using 5:xticlabel(1) w lp lw 2, '' using 6:xticlabel(1) w lp lw 2, '' using 7:xticlabel(1) w lp lw 2, '' using 8:xticlabel(1) w lp lw 2, '' using 9:xticlabel(1) w lp lw 2 +# EOF diff --git a/node_modules/request/node_modules/node-uuid/benchmark/bench.sh b/node_modules/request/node_modules/node-uuid/benchmark/bench.sh new file mode 100755 index 000000000..d870a0cb0 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/benchmark/bench.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# for a given node version run: +# for i in {0..9}; do node benchmark.js >> bench_0.6.2.log; done; + +PATTERNS=('nodeuuid.v1()' "nodeuuid.v1('binary'," 'nodeuuid.v4()' "nodeuuid.v4('binary'," "uuid()" "uuid('binary')" 'uuidjs.create(1)' 'uuidjs.create(4)' '140byte') +FILES=(node_uuid_v1_string node_uuid_v1_buf node_uuid_v4_string node_uuid_v4_buf libuuid_v4_string libuuid_v4_binary uuidjs_v1_string uuidjs_v4_string 140byte_es) +INDICES=(2 3 2 3 2 2 2 2 2) +VERSIONS=$( ls bench_*.log | sed -e 's/^bench_\([0-9\.]*\)\.log/\1/' | tr "\\n" " " ) +TMPJOIN="tmp_join" +OUTPUT="bench_results.txt" + +for I in ${!FILES[*]}; do + F=${FILES[$I]} + P=${PATTERNS[$I]} + INDEX=${INDICES[$I]} + echo "version $F" > $F + for V in $VERSIONS; do + (VAL=$( grep "$P" bench_$V.log | LC_ALL=en_US awk '{ sum += $'$INDEX' } END { print sum/NR }' ); echo $V $VAL) >> $F + done + if [ $I == 0 ]; then + cat $F > $TMPJOIN + else + join $TMPJOIN $F > $OUTPUT + cp $OUTPUT $TMPJOIN + fi + rm $F +done + +rm $TMPJOIN + +gnuplot bench.gnu +convert -density 200 -resize 800x560 -flatten bench.eps bench.png +rm bench.eps diff --git a/node_modules/request/node_modules/node-uuid/benchmark/benchmark-native.c b/node_modules/request/node_modules/node-uuid/benchmark/benchmark-native.c new file mode 100644 index 000000000..dbfc75f6d --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/benchmark/benchmark-native.c @@ -0,0 +1,34 @@ +/* +Test performance of native C UUID generation + +To Compile: cc -luuid benchmark-native.c -o benchmark-native +*/ + +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <uuid/uuid.h> + +int main() { + uuid_t myid; + char buf[36+1]; + int i; + struct timeval t; + double start, finish; + + gettimeofday(&t, NULL); + start = t.tv_sec + t.tv_usec/1e6; + + int n = 2e5; + for (i = 0; i < n; i++) { + uuid_generate(myid); + uuid_unparse(myid, buf); + } + + gettimeofday(&t, NULL); + finish = t.tv_sec + t.tv_usec/1e6; + double dur = finish - start; + + printf("%d uuids/sec", (int)(n/dur)); + return 0; +} diff --git a/node_modules/request/node_modules/node-uuid/benchmark/benchmark.js b/node_modules/request/node_modules/node-uuid/benchmark/benchmark.js new file mode 100644 index 000000000..40e6efbe7 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/benchmark/benchmark.js @@ -0,0 +1,84 @@ +try { + var nodeuuid = require('../uuid'); +} catch (e) { + console.error('node-uuid require failed - skipping tests'); +} + +try { + var uuid = require('uuid'); +} catch (e) { + console.error('uuid require failed - skipping tests'); +} + +try { + var uuidjs = require('uuid-js'); +} catch (e) { + console.error('uuid-js require failed - skipping tests'); +} + +var N = 5e5; + +function rate(msg, t) { + console.log(msg + ': ' + + (N / (Date.now() - t) * 1e3 | 0) + + ' uuids/second'); +} + +console.log('# v4'); + +// node-uuid - string form +if (nodeuuid) { + for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4(); + rate('nodeuuid.v4() - using node.js crypto RNG', t); + + for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4({rng: nodeuuid.mathRNG}); + rate('nodeuuid.v4() - using Math.random() RNG', t); + + for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4('binary'); + rate('nodeuuid.v4(\'binary\')', t); + + var buffer = new nodeuuid.BufferClass(16); + for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4('binary', buffer); + rate('nodeuuid.v4(\'binary\', buffer)', t); +} + +// libuuid - string form +if (uuid) { + for (var i = 0, t = Date.now(); i < N; i++) uuid(); + rate('uuid()', t); + + for (var i = 0, t = Date.now(); i < N; i++) uuid('binary'); + rate('uuid(\'binary\')', t); +} + +// uuid-js - string form +if (uuidjs) { + for (var i = 0, t = Date.now(); i < N; i++) uuidjs.create(4); + rate('uuidjs.create(4)', t); +} + +// 140byte.es +for (var i = 0, t = Date.now(); i < N; i++) 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(s,r){r=Math.random()*16|0;return (s=='x'?r:r&0x3|0x8).toString(16)}); +rate('140byte.es_v4', t); + +console.log(''); +console.log('# v1'); + +// node-uuid - v1 string form +if (nodeuuid) { + for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1(); + rate('nodeuuid.v1()', t); + + for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1('binary'); + rate('nodeuuid.v1(\'binary\')', t); + + var buffer = new nodeuuid.BufferClass(16); + for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1('binary', buffer); + rate('nodeuuid.v1(\'binary\', buffer)', t); +} + +// uuid-js - v1 string form +if (uuidjs) { + for (var i = 0, t = Date.now(); i < N; i++) uuidjs.create(1); + rate('uuidjs.create(1)', t); +} diff --git a/node_modules/request/node_modules/node-uuid/package.json b/node_modules/request/node_modules/node-uuid/package.json new file mode 100644 index 000000000..3c4e9acce --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/package.json @@ -0,0 +1,35 @@ +{ + "name": "node-uuid", + "description": "Rigorous implementation of RFC4122 (v1 and v4) UUIDs.", + "url": "http://github.com/broofa/node-uuid", + "keywords": [ + "uuid", + "guid", + "rfc4122" + ], + "author": { + "name": "Robert Kieffer", + "email": "robert@broofa.com" + }, + "contributors": [ + { + "name": "Christoph Tavan", + "email": "dev@tavan.de" + } + ], + "lib": ".", + "main": "./uuid.js", + "repository": { + "type": "git", + "url": "https://github.com/broofa/node-uuid.git" + }, + "version": "1.4.0", + "readme": "# node-uuid\n\nSimple, fast generation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDS.\n\nFeatures:\n\n* Generate RFC4122 version 1 or version 4 UUIDs\n* Runs in node.js and all browsers.\n* Cryptographically strong random # generation on supporting platforms\n* 1.1K minified and gzip'ed (Want something smaller? Check this [crazy shit](https://gist.github.com/982883) out! )\n* [Annotated source code](http://broofa.github.com/node-uuid/docs/uuid.html)\n\n## Getting Started\n\nInstall it in your browser:\n\n```html\n<script src=\"uuid.js\"></script>\n```\n\nOr in node.js:\n\n```\nnpm install node-uuid\n```\n\n```javascript\nvar uuid = require('node-uuid');\n```\n\nThen create some ids ...\n\n```javascript\n// Generate a v1 (time-based) id\nuuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'\n\n// Generate a v4 (random) id\nuuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'\n```\n\n## API\n\n### uuid.v1([`options` [, `buffer` [, `offset`]]])\n\nGenerate and return a RFC4122 v1 (timestamp-based) UUID.\n\n* `options` - (Object) Optional uuid state to apply. Properties may include:\n\n * `node` - (Array) Node id as Array of 6 bytes (per 4.1.6). Default: Randomly generated ID. See note 1.\n * `clockseq` - (Number between 0 - 0x3fff) RFC clock sequence. Default: An internally maintained clockseq is used.\n * `msecs` - (Number | Date) Time in milliseconds since unix Epoch. Default: The current time is used.\n * `nsecs` - (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if `msecs` is unspecified. Default: internal uuid counter is used, as per 4.2.1.2.\n\n* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written.\n* `offset` - (Number) Starting index in `buffer` at which to begin writing.\n\nReturns `buffer`, if specified, otherwise the string form of the UUID\n\nNotes:\n\n1. The randomly generated node id is only guaranteed to stay constant for the lifetime of the current JS runtime. (Future versions of this module may use persistent storage mechanisms to extend this guarantee.)\n\nExample: Generate string UUID with fully-specified options\n\n```javascript\nuuid.v1({\n node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],\n clockseq: 0x1234,\n msecs: new Date('2011-11-01').getTime(),\n nsecs: 5678\n}); // -> \"710b962e-041c-11e1-9234-0123456789ab\"\n```\n\nExample: In-place generation of two binary IDs\n\n```javascript\n// Generate two ids in an array\nvar arr = new Array(32); // -> []\nuuid.v1(null, arr, 0); // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15]\nuuid.v1(null, arr, 16); // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15 02 a3 1c b0 14 32 11 e1 85 58 0b 48 8e 4f c1 15]\n\n// Optionally use uuid.unparse() to get stringify the ids\nuuid.unparse(buffer); // -> '02a2ce90-1432-11e1-8558-0b488e4fc115'\nuuid.unparse(buffer, 16) // -> '02a31cb0-1432-11e1-8558-0b488e4fc115'\n```\n\n### uuid.v4([`options` [, `buffer` [, `offset`]]])\n\nGenerate and return a RFC4122 v4 UUID.\n\n* `options` - (Object) Optional uuid state to apply. Properties may include:\n\n * `random` - (Number[16]) Array of 16 numbers (0-255) to use in place of randomly generated values\n * `rng` - (Function) Random # generator to use. Set to one of the built-in generators - `uuid.mathRNG` (all platforms), `uuid.nodeRNG` (node.js only), `uuid.whatwgRNG` (WebKit only) - or a custom function that returns an array[16] of byte values.\n\n* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written.\n* `offset` - (Number) Starting index in `buffer` at which to begin writing.\n\nReturns `buffer`, if specified, otherwise the string form of the UUID\n\nExample: Generate string UUID with fully-specified options\n\n```javascript\nuuid.v4({\n random: [\n 0x10, 0x91, 0x56, 0xbe, 0xc4, 0xfb, 0xc1, 0xea,\n 0x71, 0xb4, 0xef, 0xe1, 0x67, 0x1c, 0x58, 0x36\n ]\n});\n// -> \"109156be-c4fb-41ea-b1b4-efe1671c5836\"\n```\n\nExample: Generate two IDs in a single buffer\n\n```javascript\nvar buffer = new Array(32); // (or 'new Buffer' in node.js)\nuuid.v4(null, buffer, 0);\nuuid.v4(null, buffer, 16);\n```\n\n### uuid.parse(id[, buffer[, offset]])\n### uuid.unparse(buffer[, offset])\n\nParse and unparse UUIDs\n\n * `id` - (String) UUID(-like) string\n * `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. Default: A new Array or Buffer is used\n * `offset` - (Number) Starting index in `buffer` at which to begin writing. Default: 0\n\nExample parsing and unparsing a UUID string\n\n```javascript\nvar bytes = uuid.parse('797ff043-11eb-11e1-80d6-510998755d10'); // -> <Buffer 79 7f f0 43 11 eb 11 e1 80 d6 51 09 98 75 5d 10>\nvar string = uuid.unparse(bytes); // -> '797ff043-11eb-11e1-80d6-510998755d10'\n```\n\n### uuid.noConflict()\n\n(Browsers only) Set `uuid` property back to it's previous value.\n\nReturns the node-uuid object.\n\nExample:\n\n```javascript\nvar myUuid = uuid.noConflict();\nmyUuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'\n```\n\n## Deprecated APIs\n\nSupport for the following v1.2 APIs is available in v1.3, but is deprecated and will be removed in the next major version.\n\n### uuid([format [, buffer [, offset]]])\n\nuuid() has become uuid.v4(), and the `format` argument is now implicit in the `buffer` argument. (i.e. if you specify a buffer, the format is assumed to be binary).\n\n### uuid.BufferClass\n\nThe class of container created when generating binary uuid data if no buffer argument is specified. This is expected to go away, with no replacement API.\n\n## Testing\n\nIn node.js\n\n```\n> cd test\n> node test.js\n```\n\nIn Browser\n\n```\nopen test/test.html\n```\n\n### Benchmarking\n\nRequires node.js\n\n```\nnpm install uuid uuid-js\nnode benchmark/benchmark.js\n```\n\nFor a more complete discussion of node-uuid performance, please see the `benchmark/README.md` file, and the [benchmark wiki](https://github.com/broofa/node-uuid/wiki/Benchmark)\n\nFor browser performance [checkout the JSPerf tests](http://jsperf.com/node-uuid-performance).\n\n## Release notes\n\nv1.4\n* Improved module context detection\n* Removed public RNG functions\n\nv1.3.2:\n* Improve tests and handling of v1() options (Issue #24)\n* Expose RNG option to allow for perf testing with different generators\n\nv1.3:\n* Support for version 1 ids, thanks to [@ctavan](https://github.com/ctavan)!\n* Support for node.js crypto API\n* De-emphasizing performance in favor of a) cryptographic quality PRNGs where available and b) more manageable code\n", + "readmeFilename": "README.md", + "_id": "node-uuid@1.4.0", + "dist": { + "shasum": "3e31c601803b006ef9a075ad64e7ea878211fbbf" + }, + "_from": "node-uuid@~1.4.0", + "_resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.0.tgz" +} diff --git a/node_modules/request/node_modules/node-uuid/test/compare_v1.js b/node_modules/request/node_modules/node-uuid/test/compare_v1.js new file mode 100644 index 000000000..05af82215 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/test/compare_v1.js @@ -0,0 +1,63 @@ +var assert = require('assert'), + nodeuuid = require('../uuid'), + uuidjs = require('uuid-js'), + libuuid = require('uuid').generate, + util = require('util'), + exec = require('child_process').exec, + os = require('os'); + +// On Mac Os X / macports there's only the ossp-uuid package that provides uuid +// On Linux there's uuid-runtime which provides uuidgen +var uuidCmd = os.type() === 'Darwin' ? 'uuid -1' : 'uuidgen -t'; + +function compare(ids) { + console.log(ids); + for (var i = 0; i < ids.length; i++) { + var id = ids[i].split('-'); + id = [id[2], id[1], id[0]].join(''); + ids[i] = id; + } + var sorted = ([].concat(ids)).sort(); + + if (sorted.toString() !== ids.toString()) { + console.log('Warning: sorted !== ids'); + } else { + console.log('everything in order!'); + } +} + +// Test time order of v1 uuids +var ids = []; +while (ids.length < 10e3) ids.push(nodeuuid.v1()); + +var max = 10; +console.log('node-uuid:'); +ids = []; +for (var i = 0; i < max; i++) ids.push(nodeuuid.v1()); +compare(ids); + +console.log(''); +console.log('uuidjs:'); +ids = []; +for (var i = 0; i < max; i++) ids.push(uuidjs.create(1).toString()); +compare(ids); + +console.log(''); +console.log('libuuid:'); +ids = []; +var count = 0; +var last = function() { + compare(ids); +} +var cb = function(err, stdout, stderr) { + ids.push(stdout.substring(0, stdout.length-1)); + count++; + if (count < max) { + return next(); + } + last(); +}; +var next = function() { + exec(uuidCmd, cb); +}; +next(); diff --git a/node_modules/request/node_modules/node-uuid/test/test.html b/node_modules/request/node_modules/node-uuid/test/test.html new file mode 100644 index 000000000..d80326ec5 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/test/test.html @@ -0,0 +1,17 @@ +<html> + <head> + <style> + div { + font-family: monospace; + font-size: 8pt; + } + div.log {color: #444;} + div.warn {color: #550;} + div.error {color: #800; font-weight: bold;} + </style> + <script src="../uuid.js"></script> + </head> + <body> + <script src="./test.js"></script> + </body> +</html> diff --git a/node_modules/request/node_modules/node-uuid/test/test.js b/node_modules/request/node_modules/node-uuid/test/test.js new file mode 100644 index 000000000..246922561 --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/test/test.js @@ -0,0 +1,228 @@ +if (!this.uuid) { + // node.js + uuid = require('../uuid'); +} + +// +// x-platform log/assert shims +// + +function _log(msg, type) { + type = type || 'log'; + + if (typeof(document) != 'undefined') { + document.write('<div class="' + type + '">' + msg.replace(/\n/g, '<br />') + '</div>'); + } + if (typeof(console) != 'undefined') { + var color = { + log: '\033[39m', + warn: '\033[33m', + error: '\033[31m' + }; + console[type](color[type] + msg + color.log); + } +} + +function log(msg) {_log(msg, 'log');} +function warn(msg) {_log(msg, 'warn');} +function error(msg) {_log(msg, 'error');} + +function assert(res, msg) { + if (!res) { + error('FAIL: ' + msg); + } else { + log('Pass: ' + msg); + } +} + +// +// Unit tests +// + +// Verify ordering of v1 ids created with explicit times +var TIME = 1321644961388; // 2011-11-18 11:36:01.388-08:00 + +function compare(name, ids) { + ids = ids.map(function(id) { + return id.split('-').reverse().join('-'); + }).sort(); + var sorted = ([].concat(ids)).sort(); + + assert(sorted.toString() == ids.toString(), name + ' have expected order'); +} + +// Verify ordering of v1 ids created using default behavior +compare('uuids with current time', [ + uuid.v1(), + uuid.v1(), + uuid.v1(), + uuid.v1(), + uuid.v1() +]); + +// Verify ordering of v1 ids created with explicit times +compare('uuids with time option', [ + uuid.v1({msecs: TIME - 10*3600*1000}), + uuid.v1({msecs: TIME - 1}), + uuid.v1({msecs: TIME}), + uuid.v1({msecs: TIME + 1}), + uuid.v1({msecs: TIME + 28*24*3600*1000}) +]); + +assert( + uuid.v1({msecs: TIME}) != uuid.v1({msecs: TIME}), + 'IDs created at same msec are different' +); + +// Verify throw if too many ids created +var thrown = false; +try { + uuid.v1({msecs: TIME, nsecs: 10000}); +} catch (e) { + thrown = true; +} +assert(thrown, 'Exception thrown when > 10K ids created in 1 ms'); + +// Verify clock regression bumps clockseq +var uidt = uuid.v1({msecs: TIME}); +var uidtb = uuid.v1({msecs: TIME - 1}); +assert( + parseInt(uidtb.split('-')[3], 16) - parseInt(uidt.split('-')[3], 16) === 1, + 'Clock regression by msec increments the clockseq' +); + +// Verify clock regression bumps clockseq +var uidtn = uuid.v1({msecs: TIME, nsecs: 10}); +var uidtnb = uuid.v1({msecs: TIME, nsecs: 9}); +assert( + parseInt(uidtnb.split('-')[3], 16) - parseInt(uidtn.split('-')[3], 16) === 1, + 'Clock regression by nsec increments the clockseq' +); + +// Verify explicit options produce expected id +var id = uuid.v1({ + msecs: 1321651533573, + nsecs: 5432, + clockseq: 0x385c, + node: [ 0x61, 0xcd, 0x3c, 0xbb, 0x32, 0x10 ] +}); +assert(id == 'd9428888-122b-11e1-b85c-61cd3cbb3210', 'Explicit options produce expected id'); + +// Verify adjacent ids across a msec boundary are 1 time unit apart +var u0 = uuid.v1({msecs: TIME, nsecs: 9999}); +var u1 = uuid.v1({msecs: TIME + 1, nsecs: 0}); + +var before = u0.split('-')[0], after = u1.split('-')[0]; +var dt = parseInt(after, 16) - parseInt(before, 16); +assert(dt === 1, 'Ids spanning 1ms boundary are 100ns apart'); + +// +// Test parse/unparse +// + +id = '00112233445566778899aabbccddeeff'; +assert(uuid.unparse(uuid.parse(id.substr(0,10))) == + '00112233-4400-0000-0000-000000000000', 'Short parse'); +assert(uuid.unparse(uuid.parse('(this is the uuid -> ' + id + id)) == + '00112233-4455-6677-8899-aabbccddeeff', 'Dirty parse'); + +// +// Perf tests +// + +var generators = { + v1: uuid.v1, + v4: uuid.v4 +}; + +var UUID_FORMAT = { + v1: /[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i, + v4: /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i +}; + +var N = 1e4; + +// Get %'age an actual value differs from the ideal value +function divergence(actual, ideal) { + return Math.round(100*100*(actual - ideal)/ideal)/100; +} + +function rate(msg, t) { + log(msg + ': ' + (N / (Date.now() - t) * 1e3 | 0) + ' uuids\/second'); +} + +for (var version in generators) { + var counts = {}, max = 0; + var generator = generators[version]; + var format = UUID_FORMAT[version]; + + log('\nSanity check ' + N + ' ' + version + ' uuids'); + for (var i = 0, ok = 0; i < N; i++) { + id = generator(); + if (!format.test(id)) { + throw Error(id + ' is not a valid UUID string'); + } + + if (id != uuid.unparse(uuid.parse(id))) { + assert(fail, id + ' is not a valid id'); + } + + // Count digits for our randomness check + if (version == 'v4') { + var digits = id.replace(/-/g, '').split(''); + for (var j = digits.length-1; j >= 0; j--) { + var c = digits[j]; + max = Math.max(max, counts[c] = (counts[c] || 0) + 1); + } + } + } + + // Check randomness for v4 UUIDs + if (version == 'v4') { + // Limit that we get worried about randomness. (Purely empirical choice, this!) + var limit = 2*100*Math.sqrt(1/N); + + log('\nChecking v4 randomness. Distribution of Hex Digits (% deviation from ideal)'); + + for (var i = 0; i < 16; i++) { + var c = i.toString(16); + var bar = '', n = counts[c], p = Math.round(n/max*100|0); + + // 1-3,5-8, and D-F: 1:16 odds over 30 digits + var ideal = N*30/16; + if (i == 4) { + // 4: 1:1 odds on 1 digit, plus 1:16 odds on 30 digits + ideal = N*(1 + 30/16); + } else if (i >= 8 && i <= 11) { + // 8-B: 1:4 odds on 1 digit, plus 1:16 odds on 30 digits + ideal = N*(1/4 + 30/16); + } else { + // Otherwise: 1:16 odds on 30 digits + ideal = N*30/16; + } + var d = divergence(n, ideal); + + // Draw bar using UTF squares (just for grins) + var s = n/max*50 | 0; + while (s--) bar += '='; + + assert(Math.abs(d) < limit, c + ' |' + bar + '| ' + counts[c] + ' (' + d + '% < ' + limit + '%)'); + } + } +} + +// Perf tests +for (var version in generators) { + log('\nPerformance testing ' + version + ' UUIDs'); + var generator = generators[version]; + var buf = new uuid.BufferClass(16); + + for (var i = 0, t = Date.now(); i < N; i++) generator(); + rate('uuid.' + version + '()', t); + + for (var i = 0, t = Date.now(); i < N; i++) generator('binary'); + rate('uuid.' + version + '(\'binary\')', t); + + for (var i = 0, t = Date.now(); i < N; i++) generator('binary', buf); + rate('uuid.' + version + '(\'binary\', buffer)', t); +} diff --git a/node_modules/request/node_modules/node-uuid/uuid.js b/node_modules/request/node_modules/node-uuid/uuid.js new file mode 100644 index 000000000..4795b9d8a --- /dev/null +++ b/node_modules/request/node_modules/node-uuid/uuid.js @@ -0,0 +1,245 @@ +// uuid.js +// +// (c) 2010-2012 Robert Kieffer +// MIT License +// https://github.com/broofa/node-uuid +(function() { + var _global = this; + + // Unique ID creation requires a high quality random # generator. We feature + // detect to determine the best RNG source, normalizing to a function that + // returns 128-bits of randomness, since that's what's usually required + var _rng; + + // Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html + // + // Moderately fast, high quality + if (typeof(require) == 'function') { + try { + var _rb = require('crypto').randomBytes; + _rng = _rb && function() {return _rb(16);}; + } catch(e) {} + } + + if (!_rng && _global.crypto && crypto.getRandomValues) { + // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto + // + // Moderately fast, high quality + var _rnds8 = new Uint8Array(16); + _rng = function whatwgRNG() { + crypto.getRandomValues(_rnds8); + return _rnds8; + }; + } + + if (!_rng) { + // Math.random()-based (RNG) + // + // If all else fails, use Math.random(). It's fast, but is of unspecified + // quality. + var _rnds = new Array(16); + _rng = function() { + for (var i = 0, r; i < 16; i++) { + if ((i & 0x03) === 0) r = Math.random() * 0x100000000; + _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff; + } + + return _rnds; + }; + } + + // Buffer class to use + var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array; + + // Maps for number <-> hex string conversion + var _byteToHex = []; + var _hexToByte = {}; + for (var i = 0; i < 256; i++) { + _byteToHex[i] = (i + 0x100).toString(16).substr(1); + _hexToByte[_byteToHex[i]] = i; + } + + // **`parse()` - Parse a UUID into it's component bytes** + function parse(s, buf, offset) { + var i = (buf && offset) || 0, ii = 0; + + buf = buf || []; + s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) { + if (ii < 16) { // Don't overflow! + buf[i + ii++] = _hexToByte[oct]; + } + }); + + // Zero out remaining bytes if string was short + while (ii < 16) { + buf[i + ii++] = 0; + } + + return buf; + } + + // **`unparse()` - Convert UUID byte array (ala parse()) into a string** + function unparse(buf, offset) { + var i = offset || 0, bth = _byteToHex; + return bth[buf[i++]] + bth[buf[i++]] + + bth[buf[i++]] + bth[buf[i++]] + '-' + + bth[buf[i++]] + bth[buf[i++]] + '-' + + bth[buf[i++]] + bth[buf[i++]] + '-' + + bth[buf[i++]] + bth[buf[i++]] + '-' + + bth[buf[i++]] + bth[buf[i++]] + + bth[buf[i++]] + bth[buf[i++]] + + bth[buf[i++]] + bth[buf[i++]]; + } + + // **`v1()` - Generate time-based UUID** + // + // Inspired by https://github.com/LiosK/UUID.js + // and http://docs.python.org/library/uuid.html + + // random #'s we need to init node and clockseq + var _seedBytes = _rng(); + + // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) + var _nodeId = [ + _seedBytes[0] | 0x01, + _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5] + ]; + + // Per 4.2.2, randomize (14 bit) clockseq + var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; + + // Previous uuid creation time + var _lastMSecs = 0, _lastNSecs = 0; + + // See https://github.com/broofa/node-uuid for API details + function v1(options, buf, offset) { + var i = buf && offset || 0; + var b = buf || []; + + options = options || {}; + + var clockseq = options.clockseq != null ? options.clockseq : _clockseq; + + // UUID timestamps are 100 nano-second units since the Gregorian epoch, + // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so + // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' + // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. + var msecs = options.msecs != null ? options.msecs : new Date().getTime(); + + // Per 4.2.1.2, use count of uuid's generated during the current clock + // cycle to simulate higher resolution clock + var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1; + + // Time since last uuid creation (in msecs) + var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000; + + // Per 4.2.1.2, Bump clockseq on clock regression + if (dt < 0 && options.clockseq == null) { + clockseq = clockseq + 1 & 0x3fff; + } + + // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new + // time interval + if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { + nsecs = 0; + } + + // Per 4.2.1.2 Throw error if too many uuids are requested + if (nsecs >= 10000) { + throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec'); + } + + _lastMSecs = msecs; + _lastNSecs = nsecs; + _clockseq = clockseq; + + // Per 4.1.4 - Convert from unix epoch to Gregorian epoch + msecs += 12219292800000; + + // `time_low` + var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; + b[i++] = tl >>> 24 & 0xff; + b[i++] = tl >>> 16 & 0xff; + b[i++] = tl >>> 8 & 0xff; + b[i++] = tl & 0xff; + + // `time_mid` + var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; + b[i++] = tmh >>> 8 & 0xff; + b[i++] = tmh & 0xff; + + // `time_high_and_version` + b[i++] = tmh >>> 24 & 0xf | 0x10; // include version + b[i++] = tmh >>> 16 & 0xff; + + // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) + b[i++] = clockseq >>> 8 | 0x80; + + // `clock_seq_low` + b[i++] = clockseq & 0xff; + + // `node` + var node = options.node || _nodeId; + for (var n = 0; n < 6; n++) { + b[i + n] = node[n]; + } + + return buf ? buf : unparse(b); + } + + // **`v4()` - Generate random UUID** + + // See https://github.com/broofa/node-uuid for API details + function v4(options, buf, offset) { + // Deprecated - 'format' argument, as supported in v1.2 + var i = buf && offset || 0; + + if (typeof(options) == 'string') { + buf = options == 'binary' ? new BufferClass(16) : null; + options = null; + } + options = options || {}; + + var rnds = options.random || (options.rng || _rng)(); + + // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + rnds[6] = (rnds[6] & 0x0f) | 0x40; + rnds[8] = (rnds[8] & 0x3f) | 0x80; + + // Copy bytes to buffer, if provided + if (buf) { + for (var ii = 0; ii < 16; ii++) { + buf[i + ii] = rnds[ii]; + } + } + + return buf || unparse(rnds); + } + + // Export public API + var uuid = v4; + uuid.v1 = v1; + uuid.v4 = v4; + uuid.parse = parse; + uuid.unparse = unparse; + uuid.BufferClass = BufferClass; + + if (_global.define && define.amd) { + // Publish as AMD module + define(function() {return uuid;}); + } else if (typeof(module) != 'undefined' && module.exports) { + // Publish as node.js module + module.exports = uuid; + } else { + // Publish as global (in browsers) + var _previousRoot = _global.uuid; + + // **`noConflict()` - (browser only) to reset global 'uuid' var** + uuid.noConflict = function() { + _global.uuid = _previousRoot; + return uuid; + }; + + _global.uuid = uuid; + } +}()); diff --git a/node_modules/request/node_modules/oauth-sign/index.js b/node_modules/request/node_modules/oauth-sign/index.js new file mode 100644 index 000000000..e35bfa670 --- /dev/null +++ b/node_modules/request/node_modules/oauth-sign/index.js @@ -0,0 +1,43 @@ +var crypto = require('crypto') + , qs = require('querystring') + ; + +function sha1 (key, body) { + return crypto.createHmac('sha1', key).update(body).digest('base64') +} + +function rfc3986 (str) { + return encodeURIComponent(str) + .replace(/!/g,'%21') + .replace(/\*/g,'%2A') + .replace(/\(/g,'%28') + .replace(/\)/g,'%29') + .replace(/'/g,'%27') + ; +} + +function hmacsign (httpMethod, base_uri, params, consumer_secret, token_secret) { + // adapted from https://dev.twitter.com/docs/auth/oauth and + // https://dev.twitter.com/docs/auth/creating-signature + + var querystring = Object.keys(params).sort().map(function(key){ + // big WTF here with the escape + encoding but it's what twitter wants + return escape(rfc3986(key)) + "%3D" + escape(rfc3986(params[key])) + }).join('%26') + + var base = [ + httpMethod ? httpMethod.toUpperCase() : 'GET', + rfc3986(base_uri), + querystring + ].join('&') + + var key = [ + consumer_secret, + token_secret || '' + ].map(rfc3986).join('&') + + return sha1(key, base) +} + +exports.hmacsign = hmacsign +exports.rfc3986 = rfc3986 diff --git a/node_modules/request/node_modules/oauth-sign/package.json b/node_modules/request/node_modules/oauth-sign/package.json new file mode 100644 index 000000000..9d1522cf1 --- /dev/null +++ b/node_modules/request/node_modules/oauth-sign/package.json @@ -0,0 +1,30 @@ +{ + "author": { + "name": "Mikeal Rogers", + "email": "mikeal.rogers@gmail.com", + "url": "http://www.futurealoof.com" + }, + "name": "oauth-sign", + "description": "OAuth 1 signing. Formerly a vendor lib in mikeal/request, now a standalone module.", + "version": "0.2.0", + "repository": { + "url": "https://github.com/mikeal/oauth-sign" + }, + "main": "index.js", + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "scripts": { + "test": "node test.js" + }, + "_id": "oauth-sign@0.2.0", + "readme": "ERROR: No README.md file found!", + "dist": { + "shasum": "67e1fe3d8a3ecd51ec085246bb3395997b618db7" + }, + "_from": "oauth-sign@~0.2.0", + "_resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.2.0.tgz" +} diff --git a/node_modules/request/node_modules/oauth-sign/test.js b/node_modules/request/node_modules/oauth-sign/test.js new file mode 100644 index 000000000..46955ff69 --- /dev/null +++ b/node_modules/request/node_modules/oauth-sign/test.js @@ -0,0 +1,49 @@ +var hmacsign = require('./index').hmacsign + , assert = require('assert') + , qs = require('querystring') + ; + +// Tests from Twitter documentation https://dev.twitter.com/docs/auth/oauth + +var reqsign = hmacsign('POST', 'https://api.twitter.com/oauth/request_token', + { oauth_callback: 'http://localhost:3005/the_dance/process_callback?service_provider_id=11' + , oauth_consumer_key: 'GDdmIQH6jhtmLUypg82g' + , oauth_nonce: 'QP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk' + , oauth_signature_method: 'HMAC-SHA1' + , oauth_timestamp: '1272323042' + , oauth_version: '1.0' + }, "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98") + +console.log(reqsign) +console.log('8wUi7m5HFQy76nowoCThusfgB+Q=') +assert.equal(reqsign, '8wUi7m5HFQy76nowoCThusfgB+Q=') + +var accsign = hmacsign('POST', 'https://api.twitter.com/oauth/access_token', + { oauth_consumer_key: 'GDdmIQH6jhtmLUypg82g' + , oauth_nonce: '9zWH6qe0qG7Lc1telCn7FhUbLyVdjEaL3MO5uHxn8' + , oauth_signature_method: 'HMAC-SHA1' + , oauth_token: '8ldIZyxQeVrFZXFOZH5tAwj6vzJYuLQpl0WUEYtWc' + , oauth_timestamp: '1272323047' + , oauth_verifier: 'pDNg57prOHapMbhv25RNf75lVRd6JDsni1AJJIDYoTY' + , oauth_version: '1.0' + }, "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98", "x6qpRnlEmW9JbQn4PQVVeVG8ZLPEx6A0TOebgwcuA") + +console.log(accsign) +console.log('PUw/dHA4fnlJYM6RhXk5IU/0fCc=') +assert.equal(accsign, 'PUw/dHA4fnlJYM6RhXk5IU/0fCc=') + +var upsign = hmacsign('POST', 'http://api.twitter.com/1/statuses/update.json', + { oauth_consumer_key: "GDdmIQH6jhtmLUypg82g" + , oauth_nonce: "oElnnMTQIZvqvlfXM56aBLAf5noGD0AQR3Fmi7Q6Y" + , oauth_signature_method: "HMAC-SHA1" + , oauth_token: "819797-Jxq8aYUDRmykzVKrgoLhXSq67TEa5ruc4GJC2rWimw" + , oauth_timestamp: "1272325550" + , oauth_version: "1.0" + , status: 'setting up my twitter 私のさえずりを設定する' + }, "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98", "J6zix3FfA9LofH0awS24M3HcBYXO5nI1iYe8EfBA") + +console.log(upsign) +console.log('yOahq5m0YjDDjfjxHaXEsW9D+X0=') +assert.equal(upsign, 'yOahq5m0YjDDjfjxHaXEsW9D+X0=') + + diff --git a/node_modules/request/node_modules/qs/.gitmodules b/node_modules/request/node_modules/qs/.gitmodules new file mode 100644 index 000000000..49e31dac7 --- /dev/null +++ b/node_modules/request/node_modules/qs/.gitmodules @@ -0,0 +1,6 @@ +[submodule "support/expresso"] + path = support/expresso + url = git://github.com/visionmedia/expresso.git +[submodule "support/should"] + path = support/should + url = git://github.com/visionmedia/should.js.git diff --git a/node_modules/request/node_modules/qs/.npmignore b/node_modules/request/node_modules/qs/.npmignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/node_modules/request/node_modules/qs/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/request/node_modules/qs/.travis.yml b/node_modules/request/node_modules/qs/.travis.yml new file mode 100644 index 000000000..2c0a8f63f --- /dev/null +++ b/node_modules/request/node_modules/qs/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.4
\ No newline at end of file diff --git a/node_modules/request/node_modules/qs/History.md b/node_modules/request/node_modules/qs/History.md new file mode 100644 index 000000000..e3721f8fb --- /dev/null +++ b/node_modules/request/node_modules/qs/History.md @@ -0,0 +1,104 @@ + +0.5.5 / 2013-03-20 +================== + + * output key= for null or undefined values. Closes #52 + +0.5.4 / 2013-03-15 +================== + + * fix ignoring of null / undefined. Closes #44 + +0.5.3 2012-12-09 +================== + + * add info to component.json + * remove regular client-side ./querystring.js, fix component.json support + +0.5.2 / 2012-11-14 +================== + + * fix uri encoding of non-plain object string values + +0.5.1 / 2012-09-18 +================== + + * fix encoded `=`. Closes #43 + +0.5.0 / 2012-05-04 +================== + + * Added component support + +0.4.2 / 2012-02-08 +================== + + * Fixed: ensure objects are created when appropriate not arrays [aheckmann] + +0.4.1 / 2012-01-26 +================== + + * Fixed stringify()ing numbers. Closes #23 + +0.4.0 / 2011-11-21 +================== + + * Allow parsing of an existing object (for `bodyParser()`) [jackyz] + * Replaced expresso with mocha + +0.3.2 / 2011-11-08 +================== + + * Fixed global variable leak + +0.3.1 / 2011-08-17 +================== + + * Added `try/catch` around malformed uri components + * Add test coverage for Array native method bleed-though + +0.3.0 / 2011-07-19 +================== + + * Allow `array[index]` and `object[property]` syntaxes [Aria Stewart] + +0.2.0 / 2011-06-29 +================== + + * Added `qs.stringify()` [Cory Forsyth] + +0.1.0 / 2011-04-13 +================== + + * Added jQuery-ish array support + +0.0.7 / 2011-03-13 +================== + + * Fixed; handle empty string and `== null` in `qs.parse()` [dmit] + allows for convenient `qs.parse(url.parse(str).query)` + +0.0.6 / 2011-02-14 +================== + + * Fixed; support for implicit arrays + +0.0.4 / 2011-02-09 +================== + + * Fixed `+` as a space + +0.0.3 / 2011-02-08 +================== + + * Fixed case when right-hand value contains "]" + +0.0.2 / 2011-02-07 +================== + + * Fixed "=" presence in key + +0.0.1 / 2011-02-07 +================== + + * Initial release diff --git a/node_modules/request/node_modules/qs/Makefile b/node_modules/request/node_modules/qs/Makefile new file mode 100644 index 000000000..84a78ec18 --- /dev/null +++ b/node_modules/request/node_modules/qs/Makefile @@ -0,0 +1,6 @@ + +test: + @./node_modules/.bin/mocha \ + --ui bdd + +.PHONY: test
\ No newline at end of file diff --git a/node_modules/request/node_modules/qs/Readme.md b/node_modules/request/node_modules/qs/Readme.md new file mode 100644 index 000000000..27e54a4af --- /dev/null +++ b/node_modules/request/node_modules/qs/Readme.md @@ -0,0 +1,58 @@ +# node-querystring + + query string parser for node and the browser supporting nesting, as it was removed from `0.3.x`, so this library provides the previous and commonly desired behaviour (and twice as fast). Used by [express](http://expressjs.com), [connect](http://senchalabs.github.com/connect) and others. + +## Installation + + $ npm install qs + +## Examples + +```js +var qs = require('qs'); + +qs.parse('user[name][first]=Tobi&user[email]=tobi@learnboost.com'); +// => { user: { name: { first: 'Tobi' }, email: 'tobi@learnboost.com' } } + +qs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }}) +// => user[name]=Tobi&user[email]=tobi%40learnboost.com +``` + +## Testing + +Install dev dependencies: + + $ npm install -d + +and execute: + + $ make test + +browser: + + $ open test/browser/index.html + +## License + +(The MIT License) + +Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/node_modules/request/node_modules/qs/benchmark.js b/node_modules/request/node_modules/qs/benchmark.js new file mode 100644 index 000000000..97e2c93ed --- /dev/null +++ b/node_modules/request/node_modules/qs/benchmark.js @@ -0,0 +1,17 @@ + +var qs = require('./'); + +var times = 100000 + , start = new Date + , n = times; + +console.log('times: %d', times); + +while (n--) qs.parse('foo=bar'); +console.log('simple: %dms', new Date - start); + +var start = new Date + , n = times; + +while (n--) qs.parse('user[name][first]=tj&user[name][last]=holowaychuk'); +console.log('nested: %dms', new Date - start);
\ No newline at end of file diff --git a/node_modules/request/node_modules/qs/component.json b/node_modules/request/node_modules/qs/component.json new file mode 100644 index 000000000..30207455f --- /dev/null +++ b/node_modules/request/node_modules/qs/component.json @@ -0,0 +1,9 @@ +{ + "name": "querystring", + "repo": "visionmedia/node-querystring", + "description": "query-string parser / stringifier with nesting support", + "version": "0.5.5", + "keywords": ["querystring", "query", "parser"], + "scripts": ["index.js"], + "license": "MIT" +} diff --git a/node_modules/request/node_modules/qs/examples.js b/node_modules/request/node_modules/qs/examples.js new file mode 100644 index 000000000..27617b75f --- /dev/null +++ b/node_modules/request/node_modules/qs/examples.js @@ -0,0 +1,51 @@ + +/** + * Module dependencies. + */ + +var qs = require('./'); + +var obj = qs.parse('foo'); +console.log(obj) + +var obj = qs.parse('foo=bar=baz'); +console.log(obj) + +var obj = qs.parse('users[]'); +console.log(obj) + +var obj = qs.parse('name=tj&email=tj@vision-media.ca'); +console.log(obj) + +var obj = qs.parse('users[]=tj&users[]=tobi&users[]=jane'); +console.log(obj) + +var obj = qs.parse('user[name][first]=tj&user[name][last]=holowaychuk'); +console.log(obj) + +var obj = qs.parse('users[][name][first]=tj&users[][name][last]=holowaychuk'); +console.log(obj) + +var obj = qs.parse('a=a&a=b&a=c'); +console.log(obj) + +var obj = qs.parse('user[tj]=tj&user[tj]=TJ'); +console.log(obj) + +var obj = qs.parse('user[names]=tj&user[names]=TJ&user[names]=Tyler'); +console.log(obj) + +var obj = qs.parse('user[name][first]=tj&user[name][first]=TJ'); +console.log(obj) + +var obj = qs.parse('user[0]=tj&user[1]=TJ'); +console.log(obj) + +var obj = qs.parse('user[0]=tj&user[]=TJ'); +console.log(obj) + +var obj = qs.parse('user[0]=tj&user[foo]=TJ'); +console.log(obj) + +var str = qs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }}); +console.log(str);
\ No newline at end of file diff --git a/node_modules/request/node_modules/qs/index.js b/node_modules/request/node_modules/qs/index.js new file mode 100644 index 000000000..35cc86128 --- /dev/null +++ b/node_modules/request/node_modules/qs/index.js @@ -0,0 +1,266 @@ + +/** + * Object#toString() ref for stringify(). + */ + +var toString = Object.prototype.toString; + +/** + * Cache non-integer test regexp. + */ + +var isint = /^[0-9]+$/; + +function promote(parent, key) { + if (parent[key].length == 0) return parent[key] = {}; + var t = {}; + for (var i in parent[key]) t[i] = parent[key][i]; + parent[key] = t; + return t; +} + +function parse(parts, parent, key, val) { + var part = parts.shift(); + // end + if (!part) { + if (Array.isArray(parent[key])) { + parent[key].push(val); + } else if ('object' == typeof parent[key]) { + parent[key] = val; + } else if ('undefined' == typeof parent[key]) { + parent[key] = val; + } else { + parent[key] = [parent[key], val]; + } + // array + } else { + var obj = parent[key] = parent[key] || []; + if (']' == part) { + if (Array.isArray(obj)) { + if ('' != val) obj.push(val); + } else if ('object' == typeof obj) { + obj[Object.keys(obj).length] = val; + } else { + obj = parent[key] = [parent[key], val]; + } + // prop + } else if (~part.indexOf(']')) { + part = part.substr(0, part.length - 1); + if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + // key + } else { + if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + } + } +} + +/** + * Merge parent key/val pair. + */ + +function merge(parent, key, val){ + if (~key.indexOf(']')) { + var parts = key.split('[') + , len = parts.length + , last = len - 1; + parse(parts, parent, 'base', val); + // optimize + } else { + if (!isint.test(key) && Array.isArray(parent.base)) { + var t = {}; + for (var k in parent.base) t[k] = parent.base[k]; + parent.base = t; + } + set(parent.base, key, val); + } + + return parent; +} + +/** + * Parse the given obj. + */ + +function parseObject(obj){ + var ret = { base: {} }; + Object.keys(obj).forEach(function(name){ + merge(ret, name, obj[name]); + }); + return ret.base; +} + +/** + * Parse the given str. + */ + +function parseString(str){ + return String(str) + .split('&') + .reduce(function(ret, pair){ + var eql = pair.indexOf('=') + , brace = lastBraceInKey(pair) + , key = pair.substr(0, brace || eql) + , val = pair.substr(brace || eql, pair.length) + , val = val.substr(val.indexOf('=') + 1, val.length); + + // ?foo + if ('' == key) key = pair, val = ''; + + return merge(ret, decode(key), decode(val)); + }, { base: {} }).base; +} + +/** + * Parse the given query `str` or `obj`, returning an object. + * + * @param {String} str | {Object} obj + * @return {Object} + * @api public + */ + +exports.parse = function(str){ + if (null == str || '' == str) return {}; + return 'object' == typeof str + ? parseObject(str) + : parseString(str); +}; + +/** + * Turn the given `obj` into a query string + * + * @param {Object} obj + * @return {String} + * @api public + */ + +var stringify = exports.stringify = function(obj, prefix) { + if (Array.isArray(obj)) { + return stringifyArray(obj, prefix); + } else if ('[object Object]' == toString.call(obj)) { + return stringifyObject(obj, prefix); + } else if ('string' == typeof obj) { + return stringifyString(obj, prefix); + } else { + return prefix + '=' + encodeURIComponent(String(obj)); + } +}; + +/** + * Stringify the given `str`. + * + * @param {String} str + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyString(str, prefix) { + if (!prefix) throw new TypeError('stringify expects an object'); + return prefix + '=' + encodeURIComponent(str); +} + +/** + * Stringify the given `arr`. + * + * @param {Array} arr + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyArray(arr, prefix) { + var ret = []; + if (!prefix) throw new TypeError('stringify expects an object'); + for (var i = 0; i < arr.length; i++) { + ret.push(stringify(arr[i], prefix + '[' + i + ']')); + } + return ret.join('&'); +} + +/** + * Stringify the given `obj`. + * + * @param {Object} obj + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyObject(obj, prefix) { + var ret = [] + , keys = Object.keys(obj) + , key; + + for (var i = 0, len = keys.length; i < len; ++i) { + key = keys[i]; + if (null == obj[key]) { + ret.push(encodeURIComponent(key) + '='); + } else { + ret.push(stringify(obj[key], prefix + ? prefix + '[' + encodeURIComponent(key) + ']' + : encodeURIComponent(key))); + } + } + + return ret.join('&'); +} + +/** + * Set `obj`'s `key` to `val` respecting + * the weird and wonderful syntax of a qs, + * where "foo=bar&foo=baz" becomes an array. + * + * @param {Object} obj + * @param {String} key + * @param {String} val + * @api private + */ + +function set(obj, key, val) { + var v = obj[key]; + if (undefined === v) { + obj[key] = val; + } else if (Array.isArray(v)) { + v.push(val); + } else { + obj[key] = [v, val]; + } +} + +/** + * Locate last brace in `str` within the key. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function lastBraceInKey(str) { + var len = str.length + , brace + , c; + for (var i = 0; i < len; ++i) { + c = str[i]; + if (']' == c) brace = false; + if ('[' == c) brace = true; + if ('=' == c && !brace) return i; + } +} + +/** + * Decode `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +function decode(str) { + try { + return decodeURIComponent(str.replace(/\+/g, ' ')); + } catch (err) { + return str; + } +} diff --git a/node_modules/request/node_modules/qs/package.json b/node_modules/request/node_modules/qs/package.json new file mode 100644 index 000000000..cc133d51a --- /dev/null +++ b/node_modules/request/node_modules/qs/package.json @@ -0,0 +1,40 @@ +{ + "name": "qs", + "description": "querystring parser", + "version": "0.5.5", + "keywords": [ + "query string", + "parser", + "component" + ], + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/node-querystring.git" + }, + "devDependencies": { + "mocha": "*", + "expect.js": "*" + }, + "component": { + "scripts": { + "querystring": "querystring.js" + } + }, + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "main": "index", + "engines": { + "node": "*" + }, + "readme": "# node-querystring\n\n query string parser for node and the browser supporting nesting, as it was removed from `0.3.x`, so this library provides the previous and commonly desired behaviour (and twice as fast). Used by [express](http://expressjs.com), [connect](http://senchalabs.github.com/connect) and others.\n\n## Installation\n\n $ npm install qs\n\n## Examples\n\n```js\nvar qs = require('qs');\n\nqs.parse('user[name][first]=Tobi&user[email]=tobi@learnboost.com');\n// => { user: { name: { first: 'Tobi' }, email: 'tobi@learnboost.com' } }\n\nqs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }})\n// => user[name]=Tobi&user[email]=tobi%40learnboost.com\n```\n\n## Testing\n\nInstall dev dependencies:\n\n $ npm install -d\n\nand execute:\n\n $ make test\n\nbrowser:\n\n $ open test/browser/index.html\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "_id": "qs@0.5.5", + "dist": { + "shasum": "e267764dfdc9cf1ec5682f1038d39e0a0af2bc5d" + }, + "_from": "qs@~0.5.4", + "_resolved": "https://registry.npmjs.org/qs/-/qs-0.5.5.tgz" +} diff --git a/node_modules/request/node_modules/qs/test/browser/expect.js b/node_modules/request/node_modules/qs/test/browser/expect.js new file mode 100644 index 000000000..76aa4e84f --- /dev/null +++ b/node_modules/request/node_modules/qs/test/browser/expect.js @@ -0,0 +1,1202 @@ + +(function (global, module) { + + if ('undefined' == typeof module) { + var module = { exports: {} } + , exports = module.exports + } + + /** + * Exports. + */ + + module.exports = expect; + expect.Assertion = Assertion; + + /** + * Exports version. + */ + + expect.version = '0.1.2'; + + /** + * Possible assertion flags. + */ + + var flags = { + not: ['to', 'be', 'have', 'include', 'only'] + , to: ['be', 'have', 'include', 'only', 'not'] + , only: ['have'] + , have: ['own'] + , be: ['an'] + }; + + function expect (obj) { + return new Assertion(obj); + } + + /** + * Constructor + * + * @api private + */ + + function Assertion (obj, flag, parent) { + this.obj = obj; + this.flags = {}; + + if (undefined != parent) { + this.flags[flag] = true; + + for (var i in parent.flags) { + if (parent.flags.hasOwnProperty(i)) { + this.flags[i] = true; + } + } + } + + var $flags = flag ? flags[flag] : keys(flags) + , self = this + + if ($flags) { + for (var i = 0, l = $flags.length; i < l; i++) { + // avoid recursion + if (this.flags[$flags[i]]) continue; + + var name = $flags[i] + , assertion = new Assertion(this.obj, name, this) + + if ('function' == typeof Assertion.prototype[name]) { + // clone the function, make sure we dont touch the prot reference + var old = this[name]; + this[name] = function () { + return old.apply(self, arguments); + } + + for (var fn in Assertion.prototype) { + if (Assertion.prototype.hasOwnProperty(fn) && fn != name) { + this[name][fn] = bind(assertion[fn], assertion); + } + } + } else { + this[name] = assertion; + } + } + } + }; + + /** + * Performs an assertion + * + * @api private + */ + + Assertion.prototype.assert = function (truth, msg, error) { + var msg = this.flags.not ? error : msg + , ok = this.flags.not ? !truth : truth; + + if (!ok) { + throw new Error(msg); + } + + this.and = new Assertion(this.obj); + }; + + /** + * Check if the value is truthy + * + * @api public + */ + + Assertion.prototype.ok = function () { + this.assert( + !!this.obj + , 'expected ' + i(this.obj) + ' to be truthy' + , 'expected ' + i(this.obj) + ' to be falsy'); + }; + + /** + * Assert that the function throws. + * + * @param {Function|RegExp} callback, or regexp to match error string against + * @api public + */ + + Assertion.prototype.throwError = + Assertion.prototype.throwException = function (fn) { + expect(this.obj).to.be.a('function'); + + var thrown = false + , not = this.flags.not + + try { + this.obj(); + } catch (e) { + if ('function' == typeof fn) { + fn(e); + } else if ('object' == typeof fn) { + var subject = 'string' == typeof e ? e : e.message; + if (not) { + expect(subject).to.not.match(fn); + } else { + expect(subject).to.match(fn); + } + } + thrown = true; + } + + if ('object' == typeof fn && not) { + // in the presence of a matcher, ensure the `not` only applies to + // the matching. + this.flags.not = false; + } + + var name = this.obj.name || 'fn'; + this.assert( + thrown + , 'expected ' + name + ' to throw an exception' + , 'expected ' + name + ' not to throw an exception'); + }; + + /** + * Checks if the array is empty. + * + * @api public + */ + + Assertion.prototype.empty = function () { + var expectation; + + if ('object' == typeof this.obj && null !== this.obj && !isArray(this.obj)) { + if ('number' == typeof this.obj.length) { + expectation = !this.obj.length; + } else { + expectation = !keys(this.obj).length; + } + } else { + if ('string' != typeof this.obj) { + expect(this.obj).to.be.an('object'); + } + + expect(this.obj).to.have.property('length'); + expectation = !this.obj.length; + } + + this.assert( + expectation + , 'expected ' + i(this.obj) + ' to be empty' + , 'expected ' + i(this.obj) + ' to not be empty'); + return this; + }; + + /** + * Checks if the obj exactly equals another. + * + * @api public + */ + + Assertion.prototype.be = + Assertion.prototype.equal = function (obj) { + this.assert( + obj === this.obj + , 'expected ' + i(this.obj) + ' to equal ' + i(obj) + , 'expected ' + i(this.obj) + ' to not equal ' + i(obj)); + return this; + }; + + /** + * Checks if the obj sortof equals another. + * + * @api public + */ + + Assertion.prototype.eql = function (obj) { + this.assert( + expect.eql(obj, this.obj) + , 'expected ' + i(this.obj) + ' to sort of equal ' + i(obj) + , 'expected ' + i(this.obj) + ' to sort of not equal ' + i(obj)); + return this; + }; + + /** + * Assert within start to finish (inclusive). + * + * @param {Number} start + * @param {Number} finish + * @api public + */ + + Assertion.prototype.within = function (start, finish) { + var range = start + '..' + finish; + this.assert( + this.obj >= start && this.obj <= finish + , 'expected ' + i(this.obj) + ' to be within ' + range + , 'expected ' + i(this.obj) + ' to not be within ' + range); + return this; + }; + + /** + * Assert typeof / instance of + * + * @api public + */ + + Assertion.prototype.a = + Assertion.prototype.an = function (type) { + if ('string' == typeof type) { + // proper english in error msg + var n = /^[aeiou]/.test(type) ? 'n' : ''; + + // typeof with support for 'array' + this.assert( + 'array' == type ? isArray(this.obj) : + 'object' == type + ? 'object' == typeof this.obj && null !== this.obj + : type == typeof this.obj + , 'expected ' + i(this.obj) + ' to be a' + n + ' ' + type + , 'expected ' + i(this.obj) + ' not to be a' + n + ' ' + type); + } else { + // instanceof + var name = type.name || 'supplied constructor'; + this.assert( + this.obj instanceof type + , 'expected ' + i(this.obj) + ' to be an instance of ' + name + , 'expected ' + i(this.obj) + ' not to be an instance of ' + name); + } + + return this; + }; + + /** + * Assert numeric value above _n_. + * + * @param {Number} n + * @api public + */ + + Assertion.prototype.greaterThan = + Assertion.prototype.above = function (n) { + this.assert( + this.obj > n + , 'expected ' + i(this.obj) + ' to be above ' + n + , 'expected ' + i(this.obj) + ' to be below ' + n); + return this; + }; + + /** + * Assert numeric value below _n_. + * + * @param {Number} n + * @api public + */ + + Assertion.prototype.lessThan = + Assertion.prototype.below = function (n) { + this.assert( + this.obj < n + , 'expected ' + i(this.obj) + ' to be below ' + n + , 'expected ' + i(this.obj) + ' to be above ' + n); + return this; + }; + + /** + * Assert string value matches _regexp_. + * + * @param {RegExp} regexp + * @api public + */ + + Assertion.prototype.match = function (regexp) { + this.assert( + regexp.exec(this.obj) + , 'expected ' + i(this.obj) + ' to match ' + regexp + , 'expected ' + i(this.obj) + ' not to match ' + regexp); + return this; + }; + + /** + * Assert property "length" exists and has value of _n_. + * + * @param {Number} n + * @api public + */ + + Assertion.prototype.length = function (n) { + expect(this.obj).to.have.property('length'); + var len = this.obj.length; + this.assert( + n == len + , 'expected ' + i(this.obj) + ' to have a length of ' + n + ' but got ' + len + , 'expected ' + i(this.obj) + ' to not have a length of ' + len); + return this; + }; + + /** + * Assert property _name_ exists, with optional _val_. + * + * @param {String} name + * @param {Mixed} val + * @api public + */ + + Assertion.prototype.property = function (name, val) { + if (this.flags.own) { + this.assert( + Object.prototype.hasOwnProperty.call(this.obj, name) + , 'expected ' + i(this.obj) + ' to have own property ' + i(name) + , 'expected ' + i(this.obj) + ' to not have own property ' + i(name)); + return this; + } + + if (this.flags.not && undefined !== val) { + if (undefined === this.obj[name]) { + throw new Error(i(this.obj) + ' has no property ' + i(name)); + } + } else { + var hasProp; + try { + hasProp = name in this.obj + } catch (e) { + hasProp = undefined !== this.obj[name] + } + + this.assert( + hasProp + , 'expected ' + i(this.obj) + ' to have a property ' + i(name) + , 'expected ' + i(this.obj) + ' to not have a property ' + i(name)); + } + + if (undefined !== val) { + this.assert( + val === this.obj[name] + , 'expected ' + i(this.obj) + ' to have a property ' + i(name) + + ' of ' + i(val) + ', but got ' + i(this.obj[name]) + , 'expected ' + i(this.obj) + ' to not have a property ' + i(name) + + ' of ' + i(val)); + } + + this.obj = this.obj[name]; + return this; + }; + + /** + * Assert that the array contains _obj_ or string contains _obj_. + * + * @param {Mixed} obj|string + * @api public + */ + + Assertion.prototype.string = + Assertion.prototype.contain = function (obj) { + if ('string' == typeof this.obj) { + this.assert( + ~this.obj.indexOf(obj) + , 'expected ' + i(this.obj) + ' to contain ' + i(obj) + , 'expected ' + i(this.obj) + ' to not contain ' + i(obj)); + } else { + this.assert( + ~indexOf(this.obj, obj) + , 'expected ' + i(this.obj) + ' to contain ' + i(obj) + , 'expected ' + i(this.obj) + ' to not contain ' + i(obj)); + } + return this; + }; + + /** + * Assert exact keys or inclusion of keys by using + * the `.own` modifier. + * + * @param {Array|String ...} keys + * @api public + */ + + Assertion.prototype.key = + Assertion.prototype.keys = function ($keys) { + var str + , ok = true; + + $keys = isArray($keys) + ? $keys + : Array.prototype.slice.call(arguments); + + if (!$keys.length) throw new Error('keys required'); + + var actual = keys(this.obj) + , len = $keys.length; + + // Inclusion + ok = every($keys, function (key) { + return ~indexOf(actual, key); + }); + + // Strict + if (!this.flags.not && this.flags.only) { + ok = ok && $keys.length == actual.length; + } + + // Key string + if (len > 1) { + $keys = map($keys, function (key) { + return i(key); + }); + var last = $keys.pop(); + str = $keys.join(', ') + ', and ' + last; + } else { + str = i($keys[0]); + } + + // Form + str = (len > 1 ? 'keys ' : 'key ') + str; + + // Have / include + str = (!this.flags.only ? 'include ' : 'only have ') + str; + + // Assertion + this.assert( + ok + , 'expected ' + i(this.obj) + ' to ' + str + , 'expected ' + i(this.obj) + ' to not ' + str); + + return this; + }; + + /** + * Function bind implementation. + */ + + function bind (fn, scope) { + return function () { + return fn.apply(scope, arguments); + } + } + + /** + * Array every compatibility + * + * @see bit.ly/5Fq1N2 + * @api public + */ + + function every (arr, fn, thisObj) { + var scope = thisObj || global; + for (var i = 0, j = arr.length; i < j; ++i) { + if (!fn.call(scope, arr[i], i, arr)) { + return false; + } + } + return true; + }; + + /** + * Array indexOf compatibility. + * + * @see bit.ly/a5Dxa2 + * @api public + */ + + function indexOf (arr, o, i) { + if (Array.prototype.indexOf) { + return Array.prototype.indexOf.call(arr, o, i); + } + + if (arr.length === undefined) { + return -1; + } + + for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0 + ; i < j && arr[i] !== o; i++); + + return j <= i ? -1 : i; + }; + + /** + * Inspects an object. + * + * @see taken from node.js `util` module (copyright Joyent, MIT license) + * @api private + */ + + function i (obj, showHidden, depth) { + var seen = []; + + function stylize (str) { + return str; + }; + + function format (value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (value && typeof value.inspect === 'function' && + // Filter out the util module, it's inspect function is special + value !== exports && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + return value.inspect(recurseTimes); + } + + // Primitive types cannot have properties + switch (typeof value) { + case 'undefined': + return stylize('undefined', 'undefined'); + + case 'string': + var simple = '\'' + json.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return stylize(simple, 'string'); + + case 'number': + return stylize('' + value, 'number'); + + case 'boolean': + return stylize('' + value, 'boolean'); + } + // For some reason typeof null is "object", so special case here. + if (value === null) { + return stylize('null', 'null'); + } + + // Look up the keys of the object. + var visible_keys = keys(value); + var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys; + + // Functions without properties can be shortcutted. + if (typeof value === 'function' && $keys.length === 0) { + if (isRegExp(value)) { + return stylize('' + value, 'regexp'); + } else { + var name = value.name ? ': ' + value.name : ''; + return stylize('[Function' + name + ']', 'special'); + } + } + + // Dates without properties can be shortcutted + if (isDate(value) && $keys.length === 0) { + return stylize(value.toUTCString(), 'date'); + } + + var base, type, braces; + // Determine the object type + if (isArray(value)) { + type = 'Array'; + braces = ['[', ']']; + } else { + type = 'Object'; + braces = ['{', '}']; + } + + // Make functions say that they are functions + if (typeof value === 'function') { + var n = value.name ? ': ' + value.name : ''; + base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']'; + } else { + base = ''; + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + value.toUTCString(); + } + + if ($keys.length === 0) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return stylize('' + value, 'regexp'); + } else { + return stylize('[Object]', 'special'); + } + } + + seen.push(value); + + var output = map($keys, function (key) { + var name, str; + if (value.__lookupGetter__) { + if (value.__lookupGetter__(key)) { + if (value.__lookupSetter__(key)) { + str = stylize('[Getter/Setter]', 'special'); + } else { + str = stylize('[Getter]', 'special'); + } + } else { + if (value.__lookupSetter__(key)) { + str = stylize('[Setter]', 'special'); + } + } + } + if (indexOf(visible_keys, key) < 0) { + name = '[' + key + ']'; + } + if (!str) { + if (indexOf(seen, value[key]) < 0) { + if (recurseTimes === null) { + str = format(value[key]); + } else { + str = format(value[key], recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (isArray(value)) { + str = map(str.split('\n'), function (line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + map(str.split('\n'), function (line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = stylize('[Circular]', 'special'); + } + } + if (typeof name === 'undefined') { + if (type === 'Array' && key.match(/^\d+$/)) { + return str; + } + name = json.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = stylize(name, 'string'); + } + } + + return name + ': ' + str; + }); + + seen.pop(); + + var numLinesEst = 0; + var length = reduce(output, function (prev, cur) { + numLinesEst++; + if (indexOf(cur, '\n') >= 0) numLinesEst++; + return prev + cur.length + 1; + }, 0); + + if (length > 50) { + output = braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + + } else { + output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; + } + + return output; + } + return format(obj, (typeof depth === 'undefined' ? 2 : depth)); + }; + + function isArray (ar) { + return Object.prototype.toString.call(ar) == '[object Array]'; + }; + + function isRegExp(re) { + var s = '' + re; + return re instanceof RegExp || // easy case + // duck-type for context-switching evalcx case + typeof(re) === 'function' && + re.constructor.name === 'RegExp' && + re.compile && + re.test && + re.exec && + s.match(/^\/.*\/[gim]{0,3}$/); + }; + + function isDate(d) { + if (d instanceof Date) return true; + return false; + }; + + function keys (obj) { + if (Object.keys) { + return Object.keys(obj); + } + + var keys = []; + + for (var i in obj) { + if (Object.prototype.hasOwnProperty.call(obj, i)) { + keys.push(i); + } + } + + return keys; + } + + function map (arr, mapper, that) { + if (Array.prototype.map) { + return Array.prototype.map.call(arr, mapper, that); + } + + var other= new Array(arr.length); + + for (var i= 0, n = arr.length; i<n; i++) + if (i in arr) + other[i] = mapper.call(that, arr[i], i, arr); + + return other; + }; + + function reduce (arr, fun) { + if (Array.prototype.reduce) { + return Array.prototype.reduce.apply( + arr + , Array.prototype.slice.call(arguments, 1) + ); + } + + var len = +this.length; + + if (typeof fun !== "function") + throw new TypeError(); + + // no value to return if no initial value and an empty array + if (len === 0 && arguments.length === 1) + throw new TypeError(); + + var i = 0; + if (arguments.length >= 2) { + var rv = arguments[1]; + } else { + do { + if (i in this) { + rv = this[i++]; + break; + } + + // if array contains no values, no initial value to return + if (++i >= len) + throw new TypeError(); + } while (true); + } + + for (; i < len; i++) { + if (i in this) + rv = fun.call(null, rv, this[i], i, this); + } + + return rv; + }; + + /** + * Asserts deep equality + * + * @see taken from node.js `assert` module (copyright Joyent, MIT license) + * @api private + */ + + expect.eql = function eql (actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + } else if ('undefined' != typeof Buffer + && Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.3. Other pairs that do not both pass typeof value == "object", + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual == expected; + + // 7.4. For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical "prototype" property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } + } + + function isUndefinedOrNull (value) { + return value === null || value === undefined; + } + + function isArguments (object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; + } + + function objEquiv (a, b) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + // an identical "prototype" property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return expect.eql(a, b); + } + try{ + var ka = keys(a), + kb = keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!expect.eql(a[key], b[key])) + return false; + } + return true; + } + + var json = (function () { + "use strict"; + + if ('object' == typeof JSON && JSON.parse && JSON.stringify) { + return { + parse: nativeJSON.parse + , stringify: nativeJSON.stringify + } + } + + var JSON = {}; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + function date(d, key) { + return isFinite(d.valueOf()) ? + d.getUTCFullYear() + '-' + + f(d.getUTCMonth() + 1) + '-' + + f(d.getUTCDate()) + 'T' + + f(d.getUTCHours()) + ':' + + f(d.getUTCMinutes()) + ':' + + f(d.getUTCSeconds()) + 'Z' : null; + }; + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + + // If the string contains no control characters, no quote characters, and no + // backslash characters, then we can safely slap some quotes around it. + // Otherwise we must also replace the offending characters with safe escape + // sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : '"' + string + '"'; + } + + + function str(key, holder) { + + // Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + + // If the value has a toJSON method, call it to obtain a replacement value. + + if (value instanceof Date) { + value = date(key); + } + + // If we were called with a replacer function, then call the replacer to + // obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + + // What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + + // JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + + // If the value is a boolean or null, convert it to a string. Note: + // typeof null does not produce 'null'. The case is included here in + // the remote chance that this gets fixed someday. + + return String(value); + + // If the type is 'object', we might be dealing with an object or an array or + // null. + + case 'object': + + // Due to a specification blunder in ECMAScript, typeof null is 'object', + // so watch out for that case. + + if (!value) { + return 'null'; + } + + // Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + + // Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + + // The value is an array. Stringify every element. Use null as a placeholder + // for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + + // Join all of the elements together, separated with commas, and wrap them in + // brackets. + + v = partial.length === 0 ? '[]' : gap ? + '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + + // If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + + // Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + + // Join all of the member texts together, separated with commas, + // and wrap them in braces. + + v = partial.length === 0 ? '{}' : gap ? + '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : + '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + + // If the JSON object does not yet have a stringify method, give it one. + + JSON.stringify = function (value, replacer, space) { + + // The stringify method takes a value and an optional replacer, and an optional + // space parameter, and returns a JSON text. The replacer can be a function + // that can replace values, or an array of strings that will select the keys. + // A default replacer method can be provided. Use of the space parameter can + // produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + + // If the space parameter is a number, make an indent string containing that + // many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + + // If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + + // If there is a replacer, it must be a function or an array. + // Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + + // Make a fake root object containing our value under the key of ''. + // Return the result of stringifying the value. + + return str('', {'': value}); + }; + + // If the JSON object does not yet have a parse method, give it one. + + JSON.parse = function (text, reviver) { + // The parse method takes a text and an optional reviver function, and returns + // a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + + // The walk method is used to recursively walk the resulting structure so + // that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + + // Parsing happens in four stages. In the first stage, we replace certain + // Unicode characters with escape sequences. JavaScript handles many characters + // incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + + // In the second stage, we run the text against regular expressions that look + // for non-JSON patterns. We are especially concerned with '()' and 'new' + // because they can cause invocation, and '=' because it can cause mutation. + // But just to be safe, we want to reject all unexpected forms. + + // We split the second stage into 4 regexp operations in order to work around + // crippling inefficiencies in IE's and Safari's regexp engines. First we + // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we + // replace all simple value tokens with ']' characters. Third, we delete all + // open brackets that follow a colon or comma or that begin the text. Finally, + // we look to see that the remaining characters are only whitespace or ']' or + // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ + .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + + // In the third stage we use the eval function to compile the text into a + // JavaScript structure. The '{' operator is subject to a syntactic ambiguity + // in JavaScript: it can begin a block or an object literal. We wrap the text + // in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + + // In the optional fourth stage, we recursively walk the new structure, passing + // each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + + // If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + + return JSON; + })(); + + if ('undefined' != typeof window) { + window.expect = module.exports; + } + +})( + this + , 'undefined' != typeof module ? module : {} + , 'undefined' != typeof exports ? exports : {} +);
\ No newline at end of file diff --git a/node_modules/request/node_modules/qs/test/browser/index.html b/node_modules/request/node_modules/qs/test/browser/index.html new file mode 100644 index 000000000..c73147aaa --- /dev/null +++ b/node_modules/request/node_modules/qs/test/browser/index.html @@ -0,0 +1,18 @@ +<html> + <head> + <title>Mocha</title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <link rel="stylesheet" href="mocha.css" /> + <script src="jquery.js" type="text/javascript"></script> + <script src="expect.js"></script> + <script src="mocha.js"></script> + <script>mocha.setup('bdd')</script> + <script src="qs.js"></script> + <script src="../parse.js"></script> + <script src="../stringify.js"></script> + <script>onload = mocha.run;</script> + </head> + <body> + <div id="mocha"></div> + </body> +</html> diff --git a/node_modules/request/node_modules/qs/test/browser/jquery.js b/node_modules/request/node_modules/qs/test/browser/jquery.js new file mode 100644 index 000000000..f3201aacb --- /dev/null +++ b/node_modules/request/node_modules/qs/test/browser/jquery.js @@ -0,0 +1,8981 @@ +/*! + * jQuery JavaScript Library v1.6.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Jun 30 14:16:56 2011 -0400 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z])/ig, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.6.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery._Deferred(); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return (new Function( "return " + data ))(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + // (xml & tmp used internally) + parseXML: function( data , xml , tmp ) { + + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + + tmp = xml.documentElement; + + if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + jQuery.error( "Invalid XML: " + data ); + } + + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Converts a dashed string to camelCased string; + // Used by both the css and data modules + camelCase: function( string ) { + return string.replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + + if ( indexOf ) { + return indexOf.call( array, elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +var // Promise methods + promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), + // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + // make sure args are available (#8421) + args = args || []; + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + always: function() { + return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + pipe: function( fnDone, fnFail ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject ); + } else { + newDefer[ action ]( returned ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + }); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = arguments, + i = 0, + length = args.length, + count = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + // Strange bug in FF4: + // Values changed onto the arguments object sometimes end up as undefined values + // outside the $.when method. Cloning the object into a fresh array solves the issue + deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); + } + }; + } + if ( length > 1 ) { + for( ; i < length; i++ ) { + if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return deferred.promise(); + } +}); + + + +jQuery.support = (function() { + + var div = document.createElement( "div" ), + documentElement = document.documentElement, + all, + a, + select, + opt, + input, + marginDiv, + support, + fragment, + body, + testElementParent, + testElement, + testElementStyle, + tds, + events, + eventName, + i, + isSupported; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName( "tbody" ).length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName( "link" ).length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains it's value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + div.innerHTML = ""; + + // Figure out if the W3C box model works as expected + div.style.width = div.style.paddingLeft = "1px"; + + body = document.getElementsByTagName( "body" )[ 0 ]; + // We use our own, invisible, body unless the body is already present + // in which case we use a div (#9239) + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0 + }; + if ( body ) { + jQuery.extend( testElementStyle, { + position: "absolute", + left: -1000, + top: -1000 + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "<div style='width:4px;'></div>"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>"; + tds = div.getElementsByTagName( "td" ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Remove the body element we added + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + } ) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + // Null connected elements to avoid leaks in IE + testElement = fragment = select = opt = body = marginDiv = div = input = null; + + return support; +})(); + +// Keep track of boxModel +jQuery.boxModel = jQuery.support.boxModel; + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([a-z])([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + return getByName ? + // Check for both converted-to-camel and non-converted data property names + thisCache[ jQuery.camelCase( name ) ] || thisCache[ name ] : + thisCache; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + if ( jQuery.support.deleteExpando || cache != window ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( data ) : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery.data( elem, deferDataKey, undefined, true ); + if ( defer && + ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && + ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery.data( elem, queueDataKey, undefined, true ) && + !jQuery.data( elem, markDataKey, undefined, true ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.resolve(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = (type || "fx") + "mark"; + jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); + if ( count ) { + jQuery.data( elem, key, count, true ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + if ( elem ) { + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type, undefined, true ); + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data), true ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + defer; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { + count++; + tmp.done( resolve ); + } + } + resolve(); + return defer.promise(); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + rinvalidChar = /\:|^on/, + formHook, boolHook; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = (value || "").split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return undefined; + } + + var isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attrFix: { + // Always normalize to ensure hook usage + tabindex: "tabIndex" + }, + + attr: function( elem, name, value, pass ) { + var nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( !("getAttribute" in elem) ) { + return jQuery.prop( elem, name, value ); + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // Normalize the name if needed + if ( notxml ) { + name = jQuery.attrFix[ name ] || name; + + hooks = jQuery.attrHooks[ name ]; + + if ( !hooks ) { + // Use boolHook for boolean attributes + if ( rboolean.test( name ) ) { + + hooks = boolHook; + + // Use formHook for forms and if the name contains certain characters + } else if ( formHook && name !== "className" && + (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) { + + hooks = formHook; + } + } + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return undefined; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, name ) { + var propName; + if ( elem.nodeType === 1 ) { + name = jQuery.attrFix[ name ] || name; + + if ( jQuery.support.getSetAttribute ) { + // Use removeAttribute in browsers that support it + elem.removeAttribute( name ); + } else { + jQuery.attr( elem, name, "" ); + elem.removeAttributeNode( elem.getAttributeNode( name ) ); + } + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { + elem[ propName ] = false; + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabIndex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + }, + // Use the value property for back compat + // Use the formHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( formHook && jQuery.nodeName( elem, "button" ) ) { + return formHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( formHook && jQuery.nodeName( elem, "button" ) ) { + return formHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return (elem[ name ] = value); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: {} +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + return jQuery.prop( elem, name ) ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !jQuery.support.getSetAttribute ) { + + // propFix is more comprehensive and contains all fixes + jQuery.attrFix = jQuery.propFix; + + // Use this for any attribute on a form in IE6/7 + formHook = jQuery.attrHooks.name = jQuery.attrHooks.title = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + // Return undefined if nodeValue is empty string + return ret && ret.nodeValue !== "" ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Check form objects in IE (multiple bugs related) + // Only use nodeValue if the attribute node exists on the form + var ret = elem.getAttributeNode( name ); + if ( ret ) { + ret.nodeValue = value; + return value; + } + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return (elem.style.cssText = "" + value); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }); +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); + } + } + }); +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspaces = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Event object or event type + var type = event.type || event, + namespaces = [], + exclusive; + + if ( type.indexOf("!") >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.exclusive = exclusive; + event.namespace = namespaces.join("."); + event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); + + // triggerHandler() and global events don't bubble or run the default action + if ( onlyHandlers || !elem ) { + event.preventDefault(); + event.stopPropagation(); + } + + // Handle a global trigger + if ( !elem ) { + // TODO: Stop taunting the data cache; remove global events and always attach to document + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + return; + } + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + event.target = elem; + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + var cur = elem, + // IE doesn't like method names with a colon (#3533, #8272) + ontype = type.indexOf(":") < 0 ? "on" + type : ""; + + // Fire event on the current element, then bubble up the DOM tree + do { + var handle = jQuery._data( cur, "handle" ); + + event.currentTarget = cur; + if ( handle ) { + handle.apply( cur, data ); + } + + // Trigger an inline bound script + if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { + event.result = false; + event.preventDefault(); + } + + // Bubble up to document, then to window + cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; + } while ( cur && !event.isPropagationStopped() ); + + // If nobody prevented the default action, do it now + if ( !event.isDefaultPrevented() ) { + var old, + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction)() check here because IE6/7 fails that test. + // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. + try { + if ( ontype && elem[ type ] ) { + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + jQuery.event.triggered = type; + elem[ type ](); + } + } catch ( ieError ) {} + + if ( old ) { + elem[ ontype ] = old; + } + + jQuery.event.triggered = undefined; + } + } + + return event.result; + }, + + handle: function( event ) { + event = jQuery.event.fix( event || window.event ); + // Snapshot the handlers list since a called handler may add/remove events. + var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), + run_all = !event.exclusive && !event.namespace, + args = Array.prototype.slice.call( arguments, 0 ); + + // Use the fix-ed Event rather than the (read-only) native event + args[0] = event; + event.currentTarget = this; + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Triggered event must 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event. + if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var eventDocument = event.target.ownerDocument || document, + doc = eventDocument.documentElement, + body = eventDocument.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + + // Check if mouse(over|out) are still within the same parent element + var related = event.relatedTarget, + inside = false, + eventType = event.type; + + event.type = event.data; + + if ( related !== this ) { + + if ( related ) { + inside = jQuery.contains( this, related ); + } + + if ( !inside ) { + + jQuery.event.handle.apply( this, arguments ); + + event.type = eventType; + } + } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( !jQuery.nodeName( this, "form" ) ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( jQuery.nodeName( elem, "select" ) ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + + function handler( donor ) { + // Donor event is always a native one; fix it and switch its type. + // Let focusin/out handler cancel the donor focus/blur event. + var e = jQuery.event.fix( donor ); + e.type = fix; + e.originalEvent = {}; + jQuery.event.trigger( e, null, e.target ); + if ( e.isDefaultPrevented() ) { + donor.preventDefault(); + } + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + var handler; + + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( arguments.length === 2 || data === false ) { + fn = data; + data = undefined; + } + + if ( name === "one" ) { + handler = function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }; + handler.guid = fn.guid || jQuery.guid++; + } else { + handler = fn; + } + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( name === "die" && !types && + origSelector && origSelector.charAt(0) === "." ) { + + context.unbind( origSelector ); + + return this; + } + + if ( data === false || jQuery.isFunction( data ) ) { + fn = data || returnFalse; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( liveMap[ type ] ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + + // Make sure not to accidentally match a child element with the same selector + if ( related && jQuery.contains( elem, related ) ) { + related = elem; + } + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); +} + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var match, + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var found, item, + filter = Expr.filter[ type ], + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + var first = match[2], + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = "<a name='" + id + "'/>"; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = "<a href='#'></a>"; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "<p class='TEST'></p>"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "<div class='test e'></div><div class='test'></div>"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( typeof selector === "string" ? + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[ selector ] ) { + matches[ selector ] = POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[ selector ]; + + if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /<tbody/i, + rhtml = /<|&#?\w+;/, + rnocache = /<(?:script|object|embed|option|style)/i, + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/, + wrapMap = { + option: [ 1, "<select multiple='multiple'>", "</select>" ], + legend: [ 1, "<fieldset>", "</fieldset>" ], + thead: [ 1, "<table>", "</table>" ], + tr: [ 2, "<table><tbody>", "</tbody></table>" ], + td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], + col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ], + area: [ 1, "<map>", "</map>" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize <link> and <script> tags normally +if ( !jQuery.support.htmlSerialize ) { + wrapMap._default = [ 1, "div<div>", "</div>" ]; +} + +jQuery.fn.extend({ + text: function( text ) { + if ( jQuery.isFunction(text) ) { + return this.each(function(i) { + var self = jQuery( this ); + + self.text( text.call(this, i, self.text()) ); + }); + } + + if ( typeof text !== "object" && text !== undefined ) { + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + } + + return jQuery.text( this ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + return this.each(function() { + jQuery( this ).wrapAll( html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + if ( this[0] && this[0].parentNode ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this ); + }); + } else if ( arguments.length ) { + var set = jQuery(arguments[0]); + set.push.apply( set, this.toArray() ); + return this.pushStack( set, "before", arguments ); + } + }, + + after: function() { + if ( this[0] && this[0].parentNode ) { + return this.domManip(arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + } else if ( arguments.length ) { + var set = this.pushStack( this, "after", arguments ); + set.push.apply( set, jQuery(arguments[0]).toArray() ); + return set; + } + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + for ( var i = 0, elem; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + jQuery.cleanData( [ elem ] ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + for ( var i = 0, elem; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName("*") ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + if ( value === undefined ) { + return this[0] && this[0].nodeType === 1 ? + this[0].innerHTML.replace(rinlinejQuery, "") : + null; + + // See if we can take a shortcut and just use innerHTML + } else if ( typeof value === "string" && !rnocache.test( value ) && + (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) && + !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) { + + value = value.replace(rxhtmlTag, "<$1></$2>"); + + try { + for ( var i = 0, l = this.length; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + if ( this[i].nodeType === 1 ) { + jQuery.cleanData( this[i].getElementsByTagName("*") ); + this[i].innerHTML = value; + } + } + + // If using innerHTML throws an exception, use the fallback method + } catch(e) { + this.empty().append( value ); + } + + } else if ( jQuery.isFunction( value ) ) { + this.each(function(i){ + var self = jQuery( this ); + + self.html( value.call(this, i, self.html()) ); + }); + + } else { + this.empty().append( value ); + } + + return this; + }, + + replaceWith: function( value ) { + if ( this[0] && this[0].parentNode ) { + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this), old = self.html(); + self.replaceWith( value.call( this, i, old ) ); + }); + } + + if ( typeof value !== "string" ) { + value = jQuery( value ).detach(); + } + + return this.each(function() { + var next = this.nextSibling, + parent = this.parentNode; + + jQuery( this ).remove(); + + if ( next ) { + jQuery(next).before( value ); + } else { + jQuery(parent).append( value ); + } + }); + } else { + return this.length ? + this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : + this; + } + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + var results, first, fragment, parent, + value = args[0], + scripts = []; + + // We can't cloneNode fragments that contain checked, in WebKit + if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) { + return this.each(function() { + jQuery(this).domManip( args, table, callback, true ); + }); + } + + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + args[0] = value.call(this, i, table ? self.html() : undefined); + self.domManip( args, table, callback ); + }); + } + + if ( this[0] ) { + parent = value && value.parentNode; + + // If we're in a fragment, just use that instead of building a new one + if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) { + results = { fragment: parent }; + + } else { + results = jQuery.buildFragment( args, this, scripts ); + } + + fragment = results.fragment; + + if ( fragment.childNodes.length === 1 ) { + first = fragment = fragment.firstChild; + } else { + first = fragment.firstChild; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + + for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) { + callback.call( + table ? + root(this[i], first) : + this[i], + // Make sure that we do not leak memory by inadvertently discarding + // the original fragment (which might have attached data) instead of + // using it; in addition, use the original fragment object for the last + // item instead of first because it can end up being emptied incorrectly + // in certain situations (Bug #8070). + // Fragments from the fragment cache must always be cloned and never used + // in place. + results.cacheable || (l > 1 && i < lastIndex) ? + jQuery.clone( fragment, true, true ) : + fragment + ); + } + } + + if ( scripts.length ) { + jQuery.each( scripts, evalScript ); + } + } + + return this; + } +}); + +function root( elem, cur ) { + return jQuery.nodeName(elem, "table") ? + (elem.getElementsByTagName("tbody")[0] || + elem.appendChild(elem.ownerDocument.createElement("tbody"))) : + elem; +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var internalKey = jQuery.expando, + oldData = jQuery.data( src ), + curData = jQuery.data( dest, oldData ); + + // Switch to use the internal data object, if it exists, for the next + // stage of data copying + if ( (oldData = oldData[ internalKey ]) ) { + var events = oldData.events; + curData = curData[ internalKey ] = jQuery.extend({}, oldData); + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( var type in events ) { + for ( var i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data ); + } + } + } + } +} + +function cloneFixAttributes( src, dest ) { + var nodeName; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + // clearAttributes removes the attributes, which we don't want, + // but also removes the attachEvent events, which we *do* want + if ( dest.clearAttributes ) { + dest.clearAttributes(); + } + + // mergeAttributes, in contrast, only merges back on the + // original attributes, not the events + if ( dest.mergeAttributes ) { + dest.mergeAttributes( src ); + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 fail to clone children inside object elements that use + // the proprietary classid attribute value (rather than the type + // attribute) to identify the type of content to display + if ( nodeName === "object" ) { + dest.outerHTML = src.outerHTML; + + } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + if ( src.checked ) { + dest.defaultChecked = dest.checked = src.checked; + } + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } + + // Event data gets referenced instead of copied if the expando + // gets copied too + dest.removeAttribute( jQuery.expando ); +} + +jQuery.buildFragment = function( args, nodes, scripts ) { + var fragment, cacheable, cacheresults, doc; + + // nodes may contain either an explicit document object, + // a jQuery collection or context object. + // If nodes[0] contains a valid object to assign to doc + if ( nodes && nodes[0] ) { + doc = nodes[0].ownerDocument || nodes[0]; + } + + // Ensure that an attr object doesn't incorrectly stand in as a document object + // Chrome and Firefox seem to allow this to occur and will throw exception + // Fixes #8950 + if ( !doc.createDocumentFragment ) { + doc = document; + } + + // Only cache "small" (1/2 KB) HTML strings that are associated with the main document + // Cloning options loses the selected state, so don't cache them + // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment + // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache + if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document && + args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) { + + cacheable = true; + + cacheresults = jQuery.fragments[ args[0] ]; + if ( cacheresults && cacheresults !== 1 ) { + fragment = cacheresults; + } + } + + if ( !fragment ) { + fragment = doc.createDocumentFragment(); + jQuery.clean( args, doc, fragment, scripts ); + } + + if ( cacheable ) { + jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1; + } + + return { fragment: fragment, cacheable: cacheable }; +}; + +jQuery.fragments = {}; + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var ret = [], + insert = jQuery( selector ), + parent = this.length === 1 && this[0].parentNode; + + if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) { + insert[ original ]( this[0] ); + return this; + + } else { + for ( var i = 0, l = insert.length; i < l; i++ ) { + var elems = (i > 0 ? this.clone(true) : this).get(); + jQuery( insert[i] )[ original ]( elems ); + ret = ret.concat( elems ); + } + + return this.pushStack( ret, name, insert.selector ); + } + }; +}); + +function getAll( elem ) { + if ( "getElementsByTagName" in elem ) { + return elem.getElementsByTagName( "*" ); + + } else if ( "querySelectorAll" in elem ) { + return elem.querySelectorAll( "*" ); + + } else { + return []; + } +} + +// Used in clean, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( elem.type === "checkbox" || elem.type === "radio" ) { + elem.defaultChecked = elem.checked; + } +} +// Finds all inputs and passes them to fixDefaultChecked +function findInputs( elem ) { + if ( jQuery.nodeName( elem, "input" ) ) { + fixDefaultChecked( elem ); + } else if ( "getElementsByTagName" in elem ) { + jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var clone = elem.cloneNode(true), + srcElements, + destElements, + i; + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + // IE copies events bound via attachEvent when using cloneNode. + // Calling detachEvent on the clone will also remove the events + // from the original. In order to get around this, we use some + // proprietary methods to clear the events. Thanks to MooTools + // guys for this hotness. + + cloneFixAttributes( elem, clone ); + + // Using Sizzle here is crazy slow, so we use getElementsByTagName + // instead + srcElements = getAll( elem ); + destElements = getAll( clone ); + + // Weird iteration because IE will replace the length property + // with an element if you are cloning the body and one of the + // elements on the page has a name or id of "length" + for ( i = 0; srcElements[i]; ++i ) { + cloneFixAttributes( srcElements[i], destElements[i] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + cloneCopyEvent( elem, clone ); + + if ( deepDataAndEvents ) { + srcElements = getAll( elem ); + destElements = getAll( clone ); + + for ( i = 0; srcElements[i]; ++i ) { + cloneCopyEvent( srcElements[i], destElements[i] ); + } + } + } + + srcElements = destElements = null; + + // Return the cloned set + return clone; + }, + + clean: function( elems, context, fragment, scripts ) { + var checkScriptType; + + context = context || document; + + // !context.createElement fails in IE with an error but returns typeof 'object' + if ( typeof context.createElement === "undefined" ) { + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + } + + var ret = [], j; + + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + if ( typeof elem === "number" ) { + elem += ""; + } + + if ( !elem ) { + continue; + } + + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + if ( !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); + } else { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1></$2>"); + + // Trim whitespace, otherwise indexOf won't work as expected + var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(), + wrap = wrapMap[ tag ] || wrapMap._default, + depth = wrap[0], + div = context.createElement("div"); + + // Go to html and back, then peel off extra wrappers + div.innerHTML = wrap[1] + elem + wrap[2]; + + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } + + // Remove IE's autoinserted <tbody> from table fragments + if ( !jQuery.support.tbody ) { + + // String was a <table>, *may* have spurious <tbody> + var hasBody = rtbody.test(elem), + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : + + // String was a bare <thead> or <tfoot> + wrap[1] === "<table>" && !hasBody ? + div.childNodes : + []; + + for ( j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + } + } + } + + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + } + + elem = div.childNodes; + } + } + + // Resets defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + var len; + if ( !jQuery.support.appendChecked ) { + if ( elem[0] && typeof (len = elem.length) === "number" ) { + for ( j = 0; j < len; j++ ) { + findInputs( elem[j] ); + } + } else { + findInputs( elem ); + } + } + + if ( elem.nodeType ) { + ret.push( elem ); + } else { + ret = jQuery.merge( ret, elem ); + } + } + + if ( fragment ) { + checkScriptType = function( elem ) { + return !elem.type || rscriptType.test( elem.type ); + }; + for ( i = 0; ret[i]; i++ ) { + if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { + scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); + + } else { + if ( ret[i].nodeType === 1 ) { + var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType ); + + ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); + } + fragment.appendChild( ret[i] ); + } + } + } + + return ret; + }, + + cleanData: function( elems ) { + var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special, + deleteExpando = jQuery.support.deleteExpando; + + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + continue; + } + + id = elem[ jQuery.expando ]; + + if ( id ) { + data = cache[ id ] && cache[ id ][ internalKey ]; + + if ( data && data.events ) { + for ( var type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + + // Null the DOM reference to avoid IE6/7/8 leak (#7054) + if ( data.handle ) { + data.handle.elem = null; + } + } + + if ( deleteExpando ) { + delete elem[ jQuery.expando ]; + + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } + + delete cache[ id ]; + } + } + } +}); + +function evalScript( i, elem ) { + if ( elem.src ) { + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + } else { + jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } +} + + + +var ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity=([^)]*)/, + // fixed for IE9, see #8346 + rupper = /([A-Z]|^ms)/g, + rnumpx = /^-?\d+(?:px)?$/i, + rnum = /^-?\d/, + rrelNum = /^[+\-]=/, + rrelNumFilter = /[^+\-\.\de]+/g, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssWidth = [ "Left", "Right" ], + cssHeight = [ "Top", "Bottom" ], + curCSS, + + getComputedStyle, + currentStyle; + +jQuery.fn.css = function( name, value ) { + // Setting 'undefined' is a no-op + if ( arguments.length === 2 && value === undefined ) { + return this; + } + + return jQuery.access( this, name, value, true, function( elem, name, value ) { + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }); +}; + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity", "opacity" ); + return ret === "" ? "1" : ret; + + } else { + return elem.style.opacity; + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, origName = jQuery.camelCase( name ), + style = elem.style, hooks = jQuery.cssHooks[ origName ]; + + name = jQuery.cssProps[ origName ] || origName; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Make sure that NaN and null values aren't set. See: #7116 + if ( type === "number" && isNaN( value ) || value == null ) { + return; + } + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && rrelNum.test( value ) ) { + value = +value.replace( rrelNumFilter, "" ) + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) { + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra ) { + var ret, hooks; + + // Make sure that we're working with the right name + name = jQuery.camelCase( name ); + hooks = jQuery.cssHooks[ name ]; + name = jQuery.cssProps[ name ] || name; + + // cssFloat needs a special treatment + if ( name === "cssFloat" ) { + name = "float"; + } + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) { + return ret; + + // Otherwise, if a way to get the computed value exists, use that + } else if ( curCSS ) { + return curCSS( elem, name ); + } + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + } +}); + +// DEPRECATED, Use jQuery.css() instead +jQuery.curCSS = jQuery.css; + +jQuery.each(["height", "width"], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + var val; + + if ( computed ) { + if ( elem.offsetWidth !== 0 ) { + return getWH( elem, name, extra ); + } else { + jQuery.swap( elem, cssShow, function() { + val = getWH( elem, name, extra ); + }); + } + + return val; + } + }, + + set: function( elem, value ) { + if ( rnumpx.test( value ) ) { + // ignore negative width and height values #1599 + value = parseFloat( value ); + + if ( value >= 0 ) { + return value + "px"; + } + + } else { + return value; + } + } + }; +}); + +if ( !jQuery.support.opacity ) { + jQuery.cssHooks.opacity = { + get: function( elem, computed ) { + // IE uses filters for opacity + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( parseFloat( RegExp.$1 ) / 100 ) + "" : + computed ? "1" : ""; + }, + + set: function( elem, value ) { + var style = elem.style, + currentStyle = elem.currentStyle; + + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + style.zoom = 1; + + // Set the alpha filter to set the opacity + var opacity = jQuery.isNaN( value ) ? + "" : + "alpha(opacity=" + value * 100 + ")", + filter = currentStyle && currentStyle.filter || style.filter || ""; + + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : + filter + " " + opacity; + } + }; +} + +jQuery(function() { + // This hook cannot be added until DOM ready because the support test + // for it is not run until after DOM ready + if ( !jQuery.support.reliableMarginRight ) { + jQuery.cssHooks.marginRight = { + get: function( elem, computed ) { + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // Work around by temporarily setting element display to inline-block + var ret; + jQuery.swap( elem, { "display": "inline-block" }, function() { + if ( computed ) { + ret = curCSS( elem, "margin-right", "marginRight" ); + } else { + ret = elem.style.marginRight; + } + }); + return ret; + } + }; + } +}); + +if ( document.defaultView && document.defaultView.getComputedStyle ) { + getComputedStyle = function( elem, name ) { + var ret, defaultView, computedStyle; + + name = name.replace( rupper, "-$1" ).toLowerCase(); + + if ( !(defaultView = elem.ownerDocument.defaultView) ) { + return undefined; + } + + if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) { + ret = computedStyle.getPropertyValue( name ); + if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { + ret = jQuery.style( elem, name ); + } + } + + return ret; + }; +} + +if ( document.documentElement.currentStyle ) { + currentStyle = function( elem, name ) { + var left, + ret = elem.currentStyle && elem.currentStyle[ name ], + rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ], + style = elem.style; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !rnumpx.test( ret ) && rnum.test( ret ) ) { + // Remember the original values + left = style.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + elem.runtimeStyle.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : (ret || 0); + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + elem.runtimeStyle.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +curCSS = getComputedStyle || currentStyle; + +function getWH( elem, name, extra ) { + + // Start with offset property + var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + which = name === "width" ? cssWidth : cssHeight; + + if ( val > 0 ) { + if ( extra !== "border" ) { + jQuery.each( which, function() { + if ( !extra ) { + val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; + } else { + val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; + } + }); + } + + return val + "px"; + } + + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ] || 0; + } + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Add padding, border, margin + if ( extra ) { + jQuery.each( which, function() { + val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; + if ( extra !== "padding" ) { + val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; + } + }); + } + + return val + "px"; +} + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.hidden = function( elem ) { + var width = elem.offsetWidth, + height = elem.offsetHeight; + + return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none"); + }; + + jQuery.expr.filters.visible = function( elem ) { + return !jQuery.expr.filters.hidden( elem ); + }; +} + + + + +var r20 = /%20/g, + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rhash = /#.*$/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL + rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + rquery = /\?/, + rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, + rselectTextarea = /^(?:select|textarea)/i, + rspacesAjax = /\s+/, + rts = /([?&])_=[^&]*/, + rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/, + + // Keep a copy of the old load method + _load = jQuery.fn.load, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Document location + ajaxLocation, + + // Document location segments + ajaxLocParts; + +// #8138, IE may throw an exception when accessing +// a field from window.location if document.domain has been set +try { + ajaxLocation = location.href; +} catch( e ) { + // Use the href attribute of an A element + // since IE will modify it given document.location + ajaxLocation = document.createElement( "a" ); + ajaxLocation.href = ""; + ajaxLocation = ajaxLocation.href; +} + +// Segment location into parts +ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + if ( jQuery.isFunction( func ) ) { + var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ), + i = 0, + length = dataTypes.length, + dataType, + list, + placeBefore; + + // For each dataType in the dataTypeExpression + for(; i < length; i++ ) { + dataType = dataTypes[ i ]; + // We control if we're asked to add before + // any existing element + placeBefore = /^\+/.test( dataType ); + if ( placeBefore ) { + dataType = dataType.substr( 1 ) || "*"; + } + list = structure[ dataType ] = structure[ dataType ] || []; + // then we add to the structure accordingly + list[ placeBefore ? "unshift" : "push" ]( func ); + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, + dataType /* internal */, inspected /* internal */ ) { + + dataType = dataType || options.dataTypes[ 0 ]; + inspected = inspected || {}; + + inspected[ dataType ] = true; + + var list = structure[ dataType ], + i = 0, + length = list ? list.length : 0, + executeOnly = ( structure === prefilters ), + selection; + + for(; i < length && ( executeOnly || !selection ); i++ ) { + selection = list[ i ]( options, originalOptions, jqXHR ); + // If we got redirected to another dataType + // we try there if executing only and not done already + if ( typeof selection === "string" ) { + if ( !executeOnly || inspected[ selection ] ) { + selection = undefined; + } else { + options.dataTypes.unshift( selection ); + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, selection, inspected ); + } + } + } + // If we're only executing or nothing was selected + // we try the catchall dataType if not done already + if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { + selection = inspectPrefiltersOrTransports( + structure, options, originalOptions, jqXHR, "*", inspected ); + } + // unnecessary when only executing (prefilters) + // but it'll be ignored by the caller in that case + return selection; +} + +jQuery.fn.extend({ + load: function( url, params, callback ) { + if ( typeof url !== "string" && _load ) { + return _load.apply( this, arguments ); + + // Don't do a request if no elements are being requested + } else if ( !this.length ) { + return this; + } + + var off = url.indexOf( " " ); + if ( off >= 0 ) { + var selector = url.slice( off, url.length ); + url = url.slice( 0, off ); + } + + // Default to a GET request + var type = "GET"; + + // If the second parameter was provided + if ( params ) { + // If it's a function + if ( jQuery.isFunction( params ) ) { + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( typeof params === "object" ) { + params = jQuery.param( params, jQuery.ajaxSettings.traditional ); + type = "POST"; + } + } + + var self = this; + + // Request the remote document + jQuery.ajax({ + url: url, + type: type, + dataType: "html", + data: params, + // Complete callback (responseText is used internally) + complete: function( jqXHR, status, responseText ) { + // Store the response as specified by the jqXHR object + responseText = jqXHR.responseText; + // If successful, inject the HTML into all the matched elements + if ( jqXHR.isResolved() ) { + // #4825: Get the actual response in case + // a dataFilter is present in ajaxSettings + jqXHR.done(function( r ) { + responseText = r; + }); + // See if a selector was specified + self.html( selector ? + // Create a dummy div to hold the results + jQuery("<div>") + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append(responseText.replace(rscript, "")) + + // Locate the specified elements + .find(selector) : + + // If not, just inject the full result + responseText ); + } + + if ( callback ) { + self.each( callback, [ responseText, status, jqXHR ] ); + } + } + }); + + return this; + }, + + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + + serializeArray: function() { + return this.map(function(){ + return this.elements ? jQuery.makeArray( this.elements ) : this; + }) + .filter(function(){ + return this.name && !this.disabled && + ( this.checked || rselectTextarea.test( this.nodeName ) || + rinput.test( this.type ) ); + }) + .map(function( i, elem ){ + var val = jQuery( this ).val(); + + return val == null ? + null : + jQuery.isArray( val ) ? + jQuery.map( val, function( val, i ){ + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }) : + { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }).get(); + } +}); + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ + jQuery.fn[ o ] = function( f ){ + return this.bind( o, f ); + }; +}); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + // shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + return jQuery.ajax({ + type: method, + url: url, + data: data, + success: callback, + dataType: type + }); + }; +}); + +jQuery.extend({ + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function ( target, settings ) { + if ( !settings ) { + // Only one parameter, we extend ajaxSettings + settings = target; + target = jQuery.extend( true, jQuery.ajaxSettings, settings ); + } else { + // target was provided, we extend into it + jQuery.extend( true, target, jQuery.ajaxSettings, settings ); + } + // Flatten fields we don't want deep extended + for( var field in { context: 1, url: 1 } ) { + if ( field in settings ) { + target[ field ] = settings[ field ]; + } else if( field in jQuery.ajaxSettings ) { + target[ field ] = jQuery.ajaxSettings[ field ]; + } + } + return target; + }, + + ajaxSettings: { + url: ajaxLocation, + isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), + global: true, + type: "GET", + contentType: "application/x-www-form-urlencoded", + processData: true, + async: true, + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + traditional: false, + headers: {}, + */ + + accepts: { + xml: "application/xml, text/xml", + html: "text/html", + text: "text/plain", + json: "application/json, text/javascript", + "*": "*/*" + }, + + contents: { + xml: /xml/, + html: /html/, + json: /json/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText" + }, + + // List of data converters + // 1) key format is "source_type destination_type" (a single space in-between) + // 2) the catchall symbol "*" can be used for source_type + converters: { + + // Convert anything to text + "* text": window.String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": jQuery.parseJSON, + + // Parse text as xml + "text xml": jQuery.parseXML + } + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + // Callbacks context + callbackContext = s.context || s, + // Context for global events + // It's the callbackContext if one was provided in the options + // and if it's a DOM node or a jQuery collection + globalEventContext = callbackContext !== s && + ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? + jQuery( callbackContext ) : jQuery.event, + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery._Deferred(), + // Status-dependent callbacks + statusCode = s.statusCode || {}, + // ifModified key + ifModifiedKey, + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + // Response headers + responseHeadersString, + responseHeaders, + // transport + transport, + // timeout handle + timeoutTimer, + // Cross-domain detection vars + parts, + // The jqXHR state + state = 0, + // To know if global events are to be dispatched + fireGlobals, + // Loop variable + i, + // Fake xhr + jqXHR = { + + readyState: 0, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( !state ) { + var lname = name.toLowerCase(); + name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Raw string + getAllResponseHeaders: function() { + return state === 2 ? responseHeadersString : null; + }, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( state === 2 ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match === undefined ? null : match; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( !state ) { + s.mimeType = type; + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + statusText = statusText || "abort"; + if ( transport ) { + transport.abort( statusText ); + } + done( 0, statusText ); + return this; + } + }; + + // Callback for when everything is done + // It is defined here because jslint complains if it is declared + // at the end of the function (which would be more logical and readable) + function done( status, statusText, responses, headers ) { + + // Called once + if ( state === 2 ) { + return; + } + + // State is "done" now + state = 2; + + // Clear timeout if it exists + if ( timeoutTimer ) { + clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status ? 4 : 0; + + var isSuccess, + success, + error, + response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined, + lastModified, + etag; + + // If successful, handle type chaining + if ( status >= 200 && status < 300 || status === 304 ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + + if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) { + jQuery.lastModified[ ifModifiedKey ] = lastModified; + } + if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) { + jQuery.etag[ ifModifiedKey ] = etag; + } + } + + // If not modified + if ( status === 304 ) { + + statusText = "notmodified"; + isSuccess = true; + + // If we have data + } else { + + try { + success = ajaxConvert( s, response ); + statusText = "success"; + isSuccess = true; + } catch(e) { + // We have a parsererror + statusText = "parsererror"; + error = e; + } + } + } else { + // We extract error from statusText + // then normalize statusText and status for non-aborts + error = statusText; + if( !statusText || status ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = statusText; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] ); + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + // Attach deferreds + deferred.promise( jqXHR ); + jqXHR.success = jqXHR.done; + jqXHR.error = jqXHR.fail; + jqXHR.complete = completeDeferred.done; + + // Status-dependent callbacks + jqXHR.statusCode = function( map ) { + if ( map ) { + var tmp; + if ( state < 2 ) { + for( tmp in map ) { + statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; + } + } else { + tmp = map[ jqXHR.status ]; + jqXHR.then( tmp, tmp ); + } + } + return this; + }; + + // Remove hash character (#7531: and string promotion) + // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) + // We also use the url parameter if available + s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); + + // Extract dataTypes list + s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax ); + + // Determine if a cross-domain request is in order + if ( s.crossDomain == null ) { + parts = rurl.exec( s.url.toLowerCase() ); + s.crossDomain = !!( parts && + ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || + ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != + ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) + ); + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefiler, stop there + if ( state === 2 ) { + return false; + } + + // We can fire global events as of now if asked to + fireGlobals = s.global; + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // If data is available, append data to url + if ( s.data ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; + } + + // Get ifModifiedKey before adding the anti-cache parameter + ifModifiedKey = s.url; + + // Add anti-cache in url if needed + if ( s.cache === false ) { + + var ts = jQuery.now(), + // try replacing _= if it is there + ret = s.url.replace( rts, "$1_=" + ts ); + + // if nothing was replaced, add timestamp to the end + s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + ifModifiedKey = ifModifiedKey || s.url; + if ( jQuery.lastModified[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); + } + if ( jQuery.etag[ ifModifiedKey ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); + } + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { + // Abort if not done already + jqXHR.abort(); + return false; + + } + + // Install callbacks on deferreds + for ( i in { success: 1, error: 1, complete: 1 } ) { + jqXHR[ i ]( s[ i ] ); + } + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = setTimeout( function(){ + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + state = 1; + transport.send( requestHeaders, done ); + } catch (e) { + // Propagate exception as error if not done + if ( status < 2 ) { + done( -1, e ); + // Simply rethrow otherwise + } else { + jQuery.error( e ); + } + } + } + + return jqXHR; + }, + + // Serialize an array of form elements or a set of + // key/values into a query string + param: function( a, traditional ) { + var s = [], + add = function( key, value ) { + // If value is a function, invoke it and return its value + value = jQuery.isFunction( value ) ? value() : value; + s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); + }; + + // Set traditional to true for jQuery <= 1.3.2 behavior. + if ( traditional === undefined ) { + traditional = jQuery.ajaxSettings.traditional; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + }); + + } else { + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( var prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ).replace( r20, "+" ); + } +}); + +function buildParams( prefix, obj, traditional, add ) { + if ( jQuery.isArray( obj ) ) { + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + // If array item is non-scalar (array or object), encode its + // numeric index to resolve deserialization ambiguity issues. + // Note that rack (as of 1.0.0) can't currently deserialize + // nested arrays properly, and attempting to do so may cause + // a server error. Possible fixes are to modify rack's + // deserialization algorithm or to provide an option or flag + // to force array serialization to be shallow. + buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add ); + } + }); + + } else if ( !traditional && obj != null && typeof obj === "object" ) { + // Serialize object item. + for ( var name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + // Serialize scalar item. + add( prefix, obj ); + } +} + +// This is still on the jQuery object... for now +// Want to move this to jQuery.ajax some day +jQuery.extend({ + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {} + +}); + +/* Handles responses to an ajax request: + * - sets all responseXXX fields accordingly + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var contents = s.contents, + dataTypes = s.dataTypes, + responseFields = s.responseFields, + ct, + type, + finalDataType, + firstDataType; + + // Fill responseXXX fields + for( type in responseFields ) { + if ( type in responses ) { + jqXHR[ responseFields[type] ] = responses[ type ]; + } + } + + // Remove auto dataType and get content-type in the process + while( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +// Chain conversions given the request and the original response +function ajaxConvert( s, response ) { + + // Apply the dataFilter if provided + if ( s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + var dataTypes = s.dataTypes, + converters = {}, + i, + key, + length = dataTypes.length, + tmp, + // Current and previous dataTypes + current = dataTypes[ 0 ], + prev, + // Conversion expression + conversion, + // Conversion function + conv, + // Conversion functions (transitive conversion) + conv1, + conv2; + + // For each dataType in the chain + for( i = 1; i < length; i++ ) { + + // Create converters map + // with lowercased keys + if ( i === 1 ) { + for( key in s.converters ) { + if( typeof key === "string" ) { + converters[ key.toLowerCase() ] = s.converters[ key ]; + } + } + } + + // Get the dataTypes + prev = current; + current = dataTypes[ i ]; + + // If current is auto dataType, update it to prev + if( current === "*" ) { + current = prev; + // If no auto and dataTypes are actually different + } else if ( prev !== "*" && prev !== current ) { + + // Get the converter + conversion = prev + " " + current; + conv = converters[ conversion ] || converters[ "* " + current ]; + + // If there is no direct converter, search transitively + if ( !conv ) { + conv2 = undefined; + for( conv1 in converters ) { + tmp = conv1.split( " " ); + if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) { + conv2 = converters[ tmp[1] + " " + current ]; + if ( conv2 ) { + conv1 = converters[ conv1 ]; + if ( conv1 === true ) { + conv = conv2; + } else if ( conv2 === true ) { + conv = conv1; + } + break; + } + } + } + } + // If we found no converter, dispatch an error + if ( !( conv || conv2 ) ) { + jQuery.error( "No conversion from " + conversion.replace(" "," to ") ); + } + // If found converter is not an equivalence + if ( conv !== true ) { + // Convert with 1 or 2 converters accordingly + response = conv ? conv( response ) : conv2( conv1(response) ); + } + } + } + return response; +} + + + + +var jsc = jQuery.now(), + jsre = /(\=)\?(&|$)|\?\?/i; + +// Default jsonp settings +jQuery.ajaxSetup({ + jsonp: "callback", + jsonpCallback: function() { + return jQuery.expando + "_" + ( jsc++ ); + } +}); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var inspectData = s.contentType === "application/x-www-form-urlencoded" && + ( typeof s.data === "string" ); + + if ( s.dataTypes[ 0 ] === "jsonp" || + s.jsonp !== false && ( jsre.test( s.url ) || + inspectData && jsre.test( s.data ) ) ) { + + var responseContainer, + jsonpCallback = s.jsonpCallback = + jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback, + previous = window[ jsonpCallback ], + url = s.url, + data = s.data, + replace = "$1" + jsonpCallback + "$2"; + + if ( s.jsonp !== false ) { + url = url.replace( jsre, replace ); + if ( s.url === url ) { + if ( inspectData ) { + data = data.replace( jsre, replace ); + } + if ( s.data === data ) { + // Add callback manually + url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback; + } + } + } + + s.url = url; + s.data = data; + + // Install callback + window[ jsonpCallback ] = function( response ) { + responseContainer = [ response ]; + }; + + // Clean-up function + jqXHR.always(function() { + // Set callback back to previous value + window[ jsonpCallback ] = previous; + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( previous ) ) { + window[ jsonpCallback ]( responseContainer[ 0 ] ); + } + }); + + // Use data converter to retrieve json after script execution + s.converters["script json"] = function() { + if ( !responseContainer ) { + jQuery.error( jsonpCallback + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // force json dataType + s.dataTypes[ 0 ] = "json"; + + // Delegate to script + return "script"; + } +}); + + + + +// Install script dataType +jQuery.ajaxSetup({ + accepts: { + script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /javascript|ecmascript/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +}); + +// Handle cache's special case and global +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + s.global = false; + } +}); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function(s) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + + var script, + head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; + + return { + + send: function( _, callback ) { + + script = document.createElement( "script" ); + + script.async = "async"; + + if ( s.scriptCharset ) { + script.charset = s.scriptCharset; + } + + script.src = s.url; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function( _, isAbort ) { + + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { + + // Handle memory leak in IE + script.onload = script.onreadystatechange = null; + + // Remove the script + if ( head && script.parentNode ) { + head.removeChild( script ); + } + + // Dereference the script + script = undefined; + + // Callback if not abort + if ( !isAbort ) { + callback( 200, "success" ); + } + } + }; + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709 and #4378). + head.insertBefore( script, head.firstChild ); + }, + + abort: function() { + if ( script ) { + script.onload( 0, 1 ); + } + } + }; + } +}); + + + + +var // #5280: Internet Explorer will keep connections alive if we don't abort on unload + xhrOnUnloadAbort = window.ActiveXObject ? function() { + // Abort all pending requests + for ( var key in xhrCallbacks ) { + xhrCallbacks[ key ]( 0, 1 ); + } + } : false, + xhrId = 0, + xhrCallbacks; + +// Functions to create xhrs +function createStandardXHR() { + try { + return new window.XMLHttpRequest(); + } catch( e ) {} +} + +function createActiveXHR() { + try { + return new window.ActiveXObject( "Microsoft.XMLHTTP" ); + } catch( e ) {} +} + +// Create the request object +// (This is still attached to ajaxSettings for backward compatibility) +jQuery.ajaxSettings.xhr = window.ActiveXObject ? + /* Microsoft failed to properly + * implement the XMLHttpRequest in IE7 (can't request local files), + * so we use the ActiveXObject when it is available + * Additionally XMLHttpRequest can be disabled in IE7/IE8 so + * we need a fallback. + */ + function() { + return !this.isLocal && createStandardXHR() || createActiveXHR(); + } : + // For all other browsers, use the standard XMLHttpRequest object + createStandardXHR; + +// Determine support properties +(function( xhr ) { + jQuery.extend( jQuery.support, { + ajax: !!xhr, + cors: !!xhr && ( "withCredentials" in xhr ) + }); +})( jQuery.ajaxSettings.xhr() ); + +// Create transport if the browser can provide an xhr +if ( jQuery.support.ajax ) { + + jQuery.ajaxTransport(function( s ) { + // Cross domain only allowed if supported through XMLHttpRequest + if ( !s.crossDomain || jQuery.support.cors ) { + + var callback; + + return { + send: function( headers, complete ) { + + // Get a new xhr + var xhr = s.xhr(), + handle, + i; + + // Open the socket + // Passing null username, generates a login popup on Opera (#2865) + if ( s.username ) { + xhr.open( s.type, s.url, s.async, s.username, s.password ); + } else { + xhr.open( s.type, s.url, s.async ); + } + + // Apply custom fields if provided + if ( s.xhrFields ) { + for ( i in s.xhrFields ) { + xhr[ i ] = s.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( s.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( s.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !s.crossDomain && !headers["X-Requested-With"] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Need an extra try/catch for cross domain requests in Firefox 3 + try { + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + } catch( _ ) {} + + // Do send the request + // This may raise an exception which is actually + // handled in jQuery.ajax (so no try/catch here) + xhr.send( ( s.hasContent && s.data ) || null ); + + // Listener + callback = function( _, isAbort ) { + + var status, + statusText, + responseHeaders, + responses, + xml; + + // Firefox throws exceptions when accessing properties + // of an xhr when a network error occured + // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) + try { + + // Was never called and is aborted or complete + if ( callback && ( isAbort || xhr.readyState === 4 ) ) { + + // Only called once + callback = undefined; + + // Do not keep as active anymore + if ( handle ) { + xhr.onreadystatechange = jQuery.noop; + if ( xhrOnUnloadAbort ) { + delete xhrCallbacks[ handle ]; + } + } + + // If it's an abort + if ( isAbort ) { + // Abort it manually if needed + if ( xhr.readyState !== 4 ) { + xhr.abort(); + } + } else { + status = xhr.status; + responseHeaders = xhr.getAllResponseHeaders(); + responses = {}; + xml = xhr.responseXML; + + // Construct response list + if ( xml && xml.documentElement /* #4958 */ ) { + responses.xml = xml; + } + responses.text = xhr.responseText; + + // Firefox throws an exception when accessing + // statusText for faulty cross-domain requests + try { + statusText = xhr.statusText; + } catch( e ) { + // We normalize with Webkit giving an empty statusText + statusText = ""; + } + + // Filter status for non standard behaviors + + // If the request is local and we have data: assume a success + // (success with no data won't get notified, that's the best we + // can do given current implementations) + if ( !status && s.isLocal && !s.crossDomain ) { + status = responses.text ? 200 : 404; + // IE - #1450: sometimes returns 1223 when it should be 204 + } else if ( status === 1223 ) { + status = 204; + } + } + } + } catch( firefoxAccessException ) { + if ( !isAbort ) { + complete( -1, firefoxAccessException ); + } + } + + // Call complete if needed + if ( responses ) { + complete( status, statusText, responses, responseHeaders ); + } + }; + + // if we're in sync mode or it's in cache + // and has been retrieved directly (IE6 & IE7) + // we need to manually fire the callback + if ( !s.async || xhr.readyState === 4 ) { + callback(); + } else { + handle = ++xhrId; + if ( xhrOnUnloadAbort ) { + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + jQuery( window ).unload( xhrOnUnloadAbort ); + } + // Add to list of active xhrs callbacks + xhrCallbacks[ handle ] = callback; + } + xhr.onreadystatechange = callback; + } + }, + + abort: function() { + if ( callback ) { + callback(0,1); + } + } + }; + } + }); +} + + + + +var elemdisplay = {}, + iframe, iframeDoc, + rfxtypes = /^(?:toggle|show|hide)$/, + rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, + timerId, + fxAttrs = [ + // height animations + [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ], + // width animations + [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], + // opacity animations + [ "opacity" ] + ], + fxNow, + requestAnimationFrame = window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame; + +jQuery.fn.extend({ + show: function( speed, easing, callback ) { + var elem, display; + + if ( speed || speed === 0 ) { + return this.animate( genFx("show", 3), speed, easing, callback); + + } else { + for ( var i = 0, j = this.length; i < j; i++ ) { + elem = this[i]; + + if ( elem.style ) { + display = elem.style.display; + + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { + display = elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( display === "" && jQuery.css( elem, "display" ) === "none" ) { + jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName)); + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( i = 0; i < j; i++ ) { + elem = this[i]; + + if ( elem.style ) { + display = elem.style.display; + + if ( display === "" || display === "none" ) { + elem.style.display = jQuery._data(elem, "olddisplay") || ""; + } + } + } + + return this; + } + }, + + hide: function( speed, easing, callback ) { + if ( speed || speed === 0 ) { + return this.animate( genFx("hide", 3), speed, easing, callback); + + } else { + for ( var i = 0, j = this.length; i < j; i++ ) { + if ( this[i].style ) { + var display = jQuery.css( this[i], "display" ); + + if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) { + jQuery._data( this[i], "olddisplay", display ); + } + } + } + + // Set the display of the elements in a second loop + // to avoid the constant reflow + for ( i = 0; i < j; i++ ) { + if ( this[i].style ) { + this[i].style.display = "none"; + } + } + + return this; + } + }, + + // Save the old toggle function + _toggle: jQuery.fn.toggle, + + toggle: function( fn, fn2, callback ) { + var bool = typeof fn === "boolean"; + + if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) { + this._toggle.apply( this, arguments ); + + } else if ( fn == null || bool ) { + this.each(function() { + var state = bool ? fn : jQuery(this).is(":hidden"); + jQuery(this)[ state ? "show" : "hide" ](); + }); + + } else { + this.animate(genFx("toggle", 3), fn, fn2, callback); + } + + return this; + }, + + fadeTo: function( speed, to, easing, callback ) { + return this.filter(":hidden").css("opacity", 0).show().end() + .animate({opacity: to}, speed, easing, callback); + }, + + animate: function( prop, speed, easing, callback ) { + var optall = jQuery.speed(speed, easing, callback); + + if ( jQuery.isEmptyObject( prop ) ) { + return this.each( optall.complete, [ false ] ); + } + + // Do not change referenced properties as per-property easing will be lost + prop = jQuery.extend( {}, prop ); + + return this[ optall.queue === false ? "each" : "queue" ](function() { + // XXX 'this' does not always have a nodeName when running the + // test suite + + if ( optall.queue === false ) { + jQuery._mark( this ); + } + + var opt = jQuery.extend( {}, optall ), + isElement = this.nodeType === 1, + hidden = isElement && jQuery(this).is(":hidden"), + name, val, p, + display, e, + parts, start, end, unit; + + // will store per property easing and be used to determine when an animation is complete + opt.animatedProperties = {}; + + for ( p in prop ) { + + // property name normalization + name = jQuery.camelCase( p ); + if ( p !== name ) { + prop[ name ] = prop[ p ]; + delete prop[ p ]; + } + + val = prop[ name ]; + + // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) + if ( jQuery.isArray( val ) ) { + opt.animatedProperties[ name ] = val[ 1 ]; + val = prop[ name ] = val[ 0 ]; + } else { + opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing'; + } + + if ( val === "hide" && hidden || val === "show" && !hidden ) { + return opt.complete.call( this ); + } + + if ( isElement && ( name === "height" || name === "width" ) ) { + // Make sure that nothing sneaks out + // Record all 3 overflow attributes because IE does not + // change the overflow attribute when overflowX and + // overflowY are set to the same value + opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ]; + + // Set display property to inline-block for height/width + // animations on inline elements that are having width/height + // animated + if ( jQuery.css( this, "display" ) === "inline" && + jQuery.css( this, "float" ) === "none" ) { + if ( !jQuery.support.inlineBlockNeedsLayout ) { + this.style.display = "inline-block"; + + } else { + display = defaultDisplay( this.nodeName ); + + // inline-level elements accept inline-block; + // block-level elements need to be inline with layout + if ( display === "inline" ) { + this.style.display = "inline-block"; + + } else { + this.style.display = "inline"; + this.style.zoom = 1; + } + } + } + } + } + + if ( opt.overflow != null ) { + this.style.overflow = "hidden"; + } + + for ( p in prop ) { + e = new jQuery.fx( this, opt, p ); + val = prop[ p ]; + + if ( rfxtypes.test(val) ) { + e[ val === "toggle" ? hidden ? "show" : "hide" : val ](); + + } else { + parts = rfxnum.exec( val ); + start = e.cur(); + + if ( parts ) { + end = parseFloat( parts[2] ); + unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" ); + + // We need to compute starting value + if ( unit !== "px" ) { + jQuery.style( this, p, (end || 1) + unit); + start = ((end || 1) / e.cur()) * start; + jQuery.style( this, p, start + unit); + } + + // If a +=/-= token was provided, we're doing a relative animation + if ( parts[1] ) { + end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start; + } + + e.custom( start, end, unit ); + + } else { + e.custom( start, val, "" ); + } + } + } + + // For JS strict compliance + return true; + }); + }, + + stop: function( clearQueue, gotoEnd ) { + if ( clearQueue ) { + this.queue([]); + } + + this.each(function() { + var timers = jQuery.timers, + i = timers.length; + // clear marker counters if we know they won't be + if ( !gotoEnd ) { + jQuery._unmark( true, this ); + } + while ( i-- ) { + if ( timers[i].elem === this ) { + if (gotoEnd) { + // force the next step to be the last + timers[i](true); + } + + timers.splice(i, 1); + } + } + }); + + // start the next in the queue if the last step wasn't forced + if ( !gotoEnd ) { + this.dequeue(); + } + + return this; + } + +}); + +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout( clearFxNow, 0 ); + return ( fxNow = jQuery.now() ); +} + +function clearFxNow() { + fxNow = undefined; +} + +// Generate parameters to create a standard animation +function genFx( type, num ) { + var obj = {}; + + jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() { + obj[ this ] = type; + }); + + return obj; +} + +// Generate shortcuts for custom animations +jQuery.each({ + slideDown: genFx("show", 1), + slideUp: genFx("hide", 1), + slideToggle: genFx("toggle", 1), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +}); + +jQuery.extend({ + speed: function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction(easing) && easing + }; + + opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : + opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default; + + // Queueing + opt.old = opt.complete; + opt.complete = function( noUnmark ) { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue !== false ) { + jQuery.dequeue( this ); + } else if ( noUnmark !== false ) { + jQuery._unmark( this ); + } + }; + + return opt; + }, + + easing: { + linear: function( p, n, firstNum, diff ) { + return firstNum + diff * p; + }, + swing: function( p, n, firstNum, diff ) { + return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum; + } + }, + + timers: [], + + fx: function( elem, options, prop ) { + this.options = options; + this.elem = elem; + this.prop = prop; + + options.orig = options.orig || {}; + } + +}); + +jQuery.fx.prototype = { + // Simple function for setting a style value + update: function() { + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this ); + }, + + // Get the current size + cur: function() { + if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) { + return this.elem[ this.prop ]; + } + + var parsed, + r = jQuery.css( this.elem, this.prop ); + // Empty strings, null, undefined and "auto" are converted to 0, + // complex values such as "rotate(1rad)" are returned as is, + // simple values such as "10px" are parsed to Float. + return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed; + }, + + // Start an animation from one number to another + custom: function( from, to, unit ) { + var self = this, + fx = jQuery.fx, + raf; + + this.startTime = fxNow || createFxNow(); + this.start = from; + this.end = to; + this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); + this.now = this.start; + this.pos = this.state = 0; + + function t( gotoEnd ) { + return self.step(gotoEnd); + } + + t.elem = this.elem; + + if ( t() && jQuery.timers.push(t) && !timerId ) { + // Use requestAnimationFrame instead of setInterval if available + if ( requestAnimationFrame ) { + timerId = true; + raf = function() { + // When timerId gets set to null at any point, this stops + if ( timerId ) { + requestAnimationFrame( raf ); + fx.tick(); + } + }; + requestAnimationFrame( raf ); + } else { + timerId = setInterval( fx.tick, fx.interval ); + } + } + }, + + // Simple 'show' function + show: function() { + // Remember where we started, so that we can go back to it later + this.options.orig[this.prop] = jQuery.style( this.elem, this.prop ); + this.options.show = true; + + // Begin the animation + // Make sure that we start at a small width/height to avoid any + // flash of content + this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur()); + + // Start by showing the element + jQuery( this.elem ).show(); + }, + + // Simple 'hide' function + hide: function() { + // Remember where we started, so that we can go back to it later + this.options.orig[this.prop] = jQuery.style( this.elem, this.prop ); + this.options.hide = true; + + // Begin the animation + this.custom(this.cur(), 0); + }, + + // Each step of an animation + step: function( gotoEnd ) { + var t = fxNow || createFxNow(), + done = true, + elem = this.elem, + options = this.options, + i, n; + + if ( gotoEnd || t >= options.duration + this.startTime ) { + this.now = this.end; + this.pos = this.state = 1; + this.update(); + + options.animatedProperties[ this.prop ] = true; + + for ( i in options.animatedProperties ) { + if ( options.animatedProperties[i] !== true ) { + done = false; + } + } + + if ( done ) { + // Reset the overflow + if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { + + jQuery.each( [ "", "X", "Y" ], function (index, value) { + elem.style[ "overflow" + value ] = options.overflow[index]; + }); + } + + // Hide the element if the "hide" operation was done + if ( options.hide ) { + jQuery(elem).hide(); + } + + // Reset the properties, if the item has been hidden or shown + if ( options.hide || options.show ) { + for ( var p in options.animatedProperties ) { + jQuery.style( elem, p, options.orig[p] ); + } + } + + // Execute the complete function + options.complete.call( elem ); + } + + return false; + + } else { + // classical easing cannot be used with an Infinity duration + if ( options.duration == Infinity ) { + this.now = t; + } else { + n = t - this.startTime; + this.state = n / options.duration; + + // Perform the easing function, defaults to swing + this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration ); + this.now = this.start + ((this.end - this.start) * this.pos); + } + // Perform the next step of the animation + this.update(); + } + + return true; + } +}; + +jQuery.extend( jQuery.fx, { + tick: function() { + for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) { + if ( !timers[i]() ) { + timers.splice(i--, 1); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + }, + + interval: 13, + + stop: function() { + clearInterval( timerId ); + timerId = null; + }, + + speeds: { + slow: 600, + fast: 200, + // Default speed + _default: 400 + }, + + step: { + opacity: function( fx ) { + jQuery.style( fx.elem, "opacity", fx.now ); + }, + + _default: function( fx ) { + if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) { + fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit; + } else { + fx.elem[ fx.prop ] = fx.now; + } + } + } +}); + +if ( jQuery.expr && jQuery.expr.filters ) { + jQuery.expr.filters.animated = function( elem ) { + return jQuery.grep(jQuery.timers, function( fn ) { + return elem === fn.elem; + }).length; + }; +} + +// Try to restore the default display value of an element +function defaultDisplay( nodeName ) { + + if ( !elemdisplay[ nodeName ] ) { + + var body = document.body, + elem = jQuery( "<" + nodeName + ">" ).appendTo( body ), + display = elem.css( "display" ); + + elem.remove(); + + // If the simple way fails, + // get element's real default display by attaching it to a temp iframe + if ( display === "none" || display === "" ) { + // No iframe to use yet, so create it + if ( !iframe ) { + iframe = document.createElement( "iframe" ); + iframe.frameBorder = iframe.width = iframe.height = 0; + } + + body.appendChild( iframe ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML + // document to it; WebKit & Firefox won't allow reusing the iframe document. + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" ); + iframeDoc.close(); + } + + elem = iframeDoc.createElement( nodeName ); + + iframeDoc.body.appendChild( elem ); + + display = jQuery.css( elem, "display" ); + + body.removeChild( iframe ); + } + + // Store the correct default display + elemdisplay[ nodeName ] = display; + } + + return elemdisplay[ nodeName ]; +} + + + + +var rtable = /^t(?:able|d|h)$/i, + rroot = /^(?:body|html)$/i; + +if ( "getBoundingClientRect" in document.documentElement ) { + jQuery.fn.offset = function( options ) { + var elem = this[0], box; + + if ( options ) { + return this.each(function( i ) { + jQuery.offset.setOffset( this, options, i ); + }); + } + + if ( !elem || !elem.ownerDocument ) { + return null; + } + + if ( elem === elem.ownerDocument.body ) { + return jQuery.offset.bodyOffset( elem ); + } + + try { + box = elem.getBoundingClientRect(); + } catch(e) {} + + var doc = elem.ownerDocument, + docElem = doc.documentElement; + + // Make sure we're not dealing with a disconnected DOM node + if ( !box || !jQuery.contains( docElem, elem ) ) { + return box ? { top: box.top, left: box.left } : { top: 0, left: 0 }; + } + + var body = doc.body, + win = getWindow(doc), + clientTop = docElem.clientTop || body.clientTop || 0, + clientLeft = docElem.clientLeft || body.clientLeft || 0, + scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop, + scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft, + top = box.top + scrollTop - clientTop, + left = box.left + scrollLeft - clientLeft; + + return { top: top, left: left }; + }; + +} else { + jQuery.fn.offset = function( options ) { + var elem = this[0]; + + if ( options ) { + return this.each(function( i ) { + jQuery.offset.setOffset( this, options, i ); + }); + } + + if ( !elem || !elem.ownerDocument ) { + return null; + } + + if ( elem === elem.ownerDocument.body ) { + return jQuery.offset.bodyOffset( elem ); + } + + jQuery.offset.initialize(); + + var computedStyle, + offsetParent = elem.offsetParent, + prevOffsetParent = elem, + doc = elem.ownerDocument, + docElem = doc.documentElement, + body = doc.body, + defaultView = doc.defaultView, + prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle, + top = elem.offsetTop, + left = elem.offsetLeft; + + while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) { + if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { + break; + } + + computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle; + top -= elem.scrollTop; + left -= elem.scrollLeft; + + if ( elem === offsetParent ) { + top += elem.offsetTop; + left += elem.offsetLeft; + + if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) { + top += parseFloat( computedStyle.borderTopWidth ) || 0; + left += parseFloat( computedStyle.borderLeftWidth ) || 0; + } + + prevOffsetParent = offsetParent; + offsetParent = elem.offsetParent; + } + + if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) { + top += parseFloat( computedStyle.borderTopWidth ) || 0; + left += parseFloat( computedStyle.borderLeftWidth ) || 0; + } + + prevComputedStyle = computedStyle; + } + + if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) { + top += body.offsetTop; + left += body.offsetLeft; + } + + if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { + top += Math.max( docElem.scrollTop, body.scrollTop ); + left += Math.max( docElem.scrollLeft, body.scrollLeft ); + } + + return { top: top, left: left }; + }; +} + +jQuery.offset = { + initialize: function() { + var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0, + html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>"; + + jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } ); + + container.innerHTML = html; + body.insertBefore( container, body.firstChild ); + innerDiv = container.firstChild; + checkDiv = innerDiv.firstChild; + td = innerDiv.nextSibling.firstChild.firstChild; + + this.doesNotAddBorder = (checkDiv.offsetTop !== 5); + this.doesAddBorderForTableAndCells = (td.offsetTop === 5); + + checkDiv.style.position = "fixed"; + checkDiv.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15); + checkDiv.style.position = checkDiv.style.top = ""; + + innerDiv.style.overflow = "hidden"; + innerDiv.style.position = "relative"; + + this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5); + + this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop); + + body.removeChild( container ); + jQuery.offset.initialize = jQuery.noop; + }, + + bodyOffset: function( body ) { + var top = body.offsetTop, + left = body.offsetLeft; + + jQuery.offset.initialize(); + + if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) { + top += parseFloat( jQuery.css(body, "marginTop") ) || 0; + left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; + } + + return { top: top, left: left }; + }, + + setOffset: function( elem, options, i ) { + var position = jQuery.css( elem, "position" ); + + // set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + var curElem = jQuery( elem ), + curOffset = curElem.offset(), + curCSSTop = jQuery.css( elem, "top" ), + curCSSLeft = jQuery.css( elem, "left" ), + calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, + props = {}, curPosition = {}, curTop, curLeft; + + // need to be able to calculate position if either top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( jQuery.isFunction( options ) ) { + options = options.call( elem, i, curOffset ); + } + + if (options.top != null) { + props.top = (options.top - curOffset.top) + curTop; + } + if (options.left != null) { + props.left = (options.left - curOffset.left) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + } else { + curElem.css( props ); + } + } +}; + + +jQuery.fn.extend({ + position: function() { + if ( !this[0] ) { + return null; + } + + var elem = this[0], + + // Get *real* offsetParent + offsetParent = this.offsetParent(), + + // Get correct offsets + offset = this.offset(), + parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; + offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; + + // Add offsetParent borders + parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; + parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + }; + }, + + offsetParent: function() { + return this.map(function() { + var offsetParent = this.offsetParent || document.body; + while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent; + }); + } +}); + + +// Create scrollLeft and scrollTop methods +jQuery.each( ["Left", "Top"], function( i, name ) { + var method = "scroll" + name; + + jQuery.fn[ method ] = function( val ) { + var elem, win; + + if ( val === undefined ) { + elem = this[ 0 ]; + + if ( !elem ) { + return null; + } + + win = getWindow( elem ); + + // Return the scroll offset + return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] : + jQuery.support.boxModel && win.document.documentElement[ method ] || + win.document.body[ method ] : + elem[ method ]; + } + + // Set the scroll offset + return this.each(function() { + win = getWindow( this ); + + if ( win ) { + win.scrollTo( + !i ? val : jQuery( win ).scrollLeft(), + i ? val : jQuery( win ).scrollTop() + ); + + } else { + this[ method ] = val; + } + }); + }; +}); + +function getWindow( elem ) { + return jQuery.isWindow( elem ) ? + elem : + elem.nodeType === 9 ? + elem.defaultView || elem.parentWindow : + false; +} + + + + +// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods +jQuery.each([ "Height", "Width" ], function( i, name ) { + + var type = name.toLowerCase(); + + // innerHeight and innerWidth + jQuery.fn[ "inner" + name ] = function() { + var elem = this[0]; + return elem && elem.style ? + parseFloat( jQuery.css( elem, type, "padding" ) ) : + null; + }; + + // outerHeight and outerWidth + jQuery.fn[ "outer" + name ] = function( margin ) { + var elem = this[0]; + return elem && elem.style ? + parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) : + null; + }; + + jQuery.fn[ type ] = function( size ) { + // Get window width or height + var elem = this[0]; + if ( !elem ) { + return size == null ? null : this; + } + + if ( jQuery.isFunction( size ) ) { + return this.each(function( i ) { + var self = jQuery( this ); + self[ type ]( size.call( this, i, self[ type ]() ) ); + }); + } + + if ( jQuery.isWindow( elem ) ) { + // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode + // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat + var docElemProp = elem.document.documentElement[ "client" + name ]; + return elem.document.compatMode === "CSS1Compat" && docElemProp || + elem.document.body[ "client" + name ] || docElemProp; + + // Get document width or height + } else if ( elem.nodeType === 9 ) { + // Either scroll[Width/Height] or offset[Width/Height], whichever is greater + return Math.max( + elem.documentElement["client" + name], + elem.body["scroll" + name], elem.documentElement["scroll" + name], + elem.body["offset" + name], elem.documentElement["offset" + name] + ); + + // Get or set width or height on the element + } else if ( size === undefined ) { + var orig = jQuery.css( elem, type ), + ret = parseFloat( orig ); + + return jQuery.isNaN( ret ) ? orig : ret; + + // Set the width or height on the element (default to pixels if value is unitless) + } else { + return this.css( type, typeof size === "string" ? size : size + "px" ); + } + }; + +}); + + +// Expose jQuery to the global object +window.jQuery = window.$ = jQuery; +})(window); diff --git a/node_modules/request/node_modules/qs/test/browser/mocha.css b/node_modules/request/node_modules/qs/test/browser/mocha.css new file mode 100644 index 000000000..efe1cf931 --- /dev/null +++ b/node_modules/request/node_modules/qs/test/browser/mocha.css @@ -0,0 +1,163 @@ + +body { + font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; + padding: 60px 50px; +} + +#mocha h1, h2 { + margin: 0; +} + +#mocha h1 { + margin-top: 15px; + font-size: 1em; + font-weight: 200; +} + +#mocha .suite .suite h1 { + margin-top: 0; + font-size: .8em; +} + +#mocha h2 { + font-size: 12px; + font-weight: normal; + cursor: pointer; +} + +#mocha .suite { + margin-left: 15px; +} + +#mocha .test { + margin-left: 15px; +} + +#mocha .test:hover h2::after { + position: relative; + top: 0; + right: -10px; + content: '(view source)'; + font-size: 12px; + font-family: arial; + color: #888; +} + +#mocha .test.pending:hover h2::after { + content: '(pending)'; + font-family: arial; +} + +#mocha .test.pass.medium .duration { + background: #C09853; +} + +#mocha .test.pass.slow .duration { + background: #B94A48; +} + +#mocha .test.pass::before { + content: '✓'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; +} + +#mocha .test.pass .duration { + font-size: 9px; + margin-left: 5px; + padding: 2px 5px; + color: white; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; +} + +#mocha .test.pass.fast .duration { + display: none; +} + +#mocha .test.pending { + color: #0b97c4; +} + +#mocha .test.pending::before { + content: '◦'; + color: #0b97c4; +} + +#mocha .test.fail { + color: #c00; +} + +#mocha .test.fail pre { + color: black; +} + +#mocha .test.fail::before { + content: '✖'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #c00; +} + +#mocha .test pre.error { + color: #c00; +} + +#mocha .test pre { + display: inline-block; + font: 12px/1.5 monaco, monospace; + margin: 5px; + padding: 15px; + border: 1px solid #eee; + border-bottom-color: #ddd; + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 3px #eee; +} + +#error { + color: #c00; + font-size: 1.5 em; + font-weight: 100; + letter-spacing: 1px; +} + +#stats { + position: fixed; + top: 15px; + right: 10px; + font-size: 12px; + margin: 0; + color: #888; +} + +#stats .progress { + float: right; + padding-top: 0; +} + +#stats em { + color: black; +} + +#stats li { + display: inline-block; + margin: 0 5px; + list-style: none; + padding-top: 11px; +} + +code .comment { color: #ddd } +code .init { color: #2F6FAD } +code .string { color: #5890AD } +code .keyword { color: #8A6343 } +code .number { color: #2F6FAD } diff --git a/node_modules/request/node_modules/qs/test/browser/mocha.js b/node_modules/request/node_modules/qs/test/browser/mocha.js new file mode 100644 index 000000000..1b72319a6 --- /dev/null +++ b/node_modules/request/node_modules/qs/test/browser/mocha.js @@ -0,0 +1,4201 @@ +;(function(){ + + +// CommonJS require() + +function require(p){ + var path = require.resolve(p) + , mod = require.modules[path]; + if (!mod) throw new Error('failed to require "' + p + '"'); + if (!mod.exports) { + mod.exports = {}; + mod.call(mod.exports, mod, mod.exports, require.relative(path)); + } + return mod.exports; + } + +require.modules = {}; + +require.resolve = function (path){ + var orig = path + , reg = path + '.js' + , index = path + '/index.js'; + return require.modules[reg] && reg + || require.modules[index] && index + || orig; + }; + +require.register = function (path, fn){ + require.modules[path] = fn; + }; + +require.relative = function (parent) { + return function(p){ + if ('.' != p.charAt(0)) return require(p); + + var path = parent.split('/') + , segs = p.split('/'); + path.pop(); + + for (var i = 0; i < segs.length; i++) { + var seg = segs[i]; + if ('..' == seg) path.pop(); + else if ('.' != seg) path.push(seg); + } + + return require(path.join('/')); + }; + }; + + +require.register("browser/debug.js", function(module, exports, require){ + +module.exports = function(type){ + return function(){ + + } +}; +}); // module: browser/debug.js + +require.register("browser/diff.js", function(module, exports, require){ + +}); // module: browser/diff.js + +require.register("browser/events.js", function(module, exports, require){ + +/** + * Module exports. + */ + +exports.EventEmitter = EventEmitter; + +/** + * Check if `obj` is an array. + */ + +function isArray(obj) { + return '[object Array]' == {}.toString.call(obj); +} + +/** + * Event emitter constructor. + * + * @api public. + */ + +function EventEmitter(){}; + +/** + * Adds a listener. + * + * @api public + */ + +EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; +}; + +EventEmitter.prototype.addListener = EventEmitter.prototype.on; + +/** + * Adds a volatile listener. + * + * @api public + */ + +EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; +}; + +/** + * Removes a listener. + * + * @api public + */ + +EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; +}; + +/** + * Removes all listeners for an event. + * + * @api public + */ + +EventEmitter.prototype.removeAllListeners = function (name) { + if (name === undefined) { + this.$events = {}; + return this; + } + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; +}; + +/** + * Gets all listeners for a certain event. + * + * @api publci + */ + +EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; +}; + +/** + * Emits an event. + * + * @api public + */ + +EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = [].slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; +}; +}); // module: browser/events.js + +require.register("browser/fs.js", function(module, exports, require){ + +}); // module: browser/fs.js + +require.register("browser/path.js", function(module, exports, require){ + +}); // module: browser/path.js + +require.register("browser/progress.js", function(module, exports, require){ + +/** + * Expose `Progress`. + */ + +module.exports = Progress; + +/** + * Initialize a new `Progress` indicator. + */ + +function Progress() { + this.percent = 0; + this.size(0); + this.fontSize(11); + this.font('helvetica, arial, sans-serif'); +} + +/** + * Set progress size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.size = function(n){ + this._size = n; + return this; +}; + +/** + * Set text to `str`. + * + * @param {String} str + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.text = function(str){ + this._text = str; + return this; +}; + +/** + * Set font size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.fontSize = function(n){ + this._fontSize = n; + return this; +}; + +/** + * Set font `family`. + * + * @param {String} family + * @return {Progress} for chaining + */ + +Progress.prototype.font = function(family){ + this._font = family; + return this; +}; + +/** + * Update percentage to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + */ + +Progress.prototype.update = function(n){ + this.percent = n; + return this; +}; + +/** + * Draw on `ctx`. + * + * @param {CanvasRenderingContext2d} ctx + * @return {Progress} for chaining + */ + +Progress.prototype.draw = function(ctx){ + var percent = Math.min(this.percent, 100) + , size = this._size + , half = size / 2 + , x = half + , y = half + , rad = half - 1 + , fontSize = this._fontSize; + + ctx.font = fontSize + 'px ' + this._font; + + var angle = Math.PI * 2 * (percent / 100); + ctx.clearRect(0, 0, size, size); + + // outer circle + ctx.strokeStyle = '#9f9f9f'; + ctx.beginPath(); + ctx.arc(x, y, rad, 0, angle, false); + ctx.stroke(); + + // inner circle + ctx.strokeStyle = '#eee'; + ctx.beginPath(); + ctx.arc(x, y, rad - 1, 0, angle, true); + ctx.stroke(); + + // text + var text = this._text || (percent | 0) + '%' + , w = ctx.measureText(text).width; + + ctx.fillText( + text + , x - w / 2 + 1 + , y + fontSize / 2 - 1); + + return this; +}; + +}); // module: browser/progress.js + +require.register("browser/tty.js", function(module, exports, require){ + +exports.isatty = function(){ + return true; +}; + +exports.getWindowSize = function(){ + return [window.innerHeight, window.innerWidth]; +}; +}); // module: browser/tty.js + +require.register("context.js", function(module, exports, require){ + +/** + * Expose `Context`. + */ + +module.exports = Context; + +/** + * Initialize a new `Context`. + * + * @api private + */ + +function Context(){} + +/** + * Set the context `Runnable` to `runnable`. + * + * @param {Runnable} runnable + * @return {Context} + * @api private + */ + +Context.prototype.runnable = function(runnable){ + this._runnable = runnable; + return this; +}; + +/** + * Set test timeout `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.timeout = function(ms){ + this._runnable.timeout(ms); + return this; +}; + +/** + * Inspect the context void of `._runnable`. + * + * @return {String} + * @api private + */ + +Context.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + return '_runnable' == key + ? undefined + : val; + }, 2); +}; + +}); // module: context.js + +require.register("hook.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Hook`. + */ + +module.exports = Hook; + +/** + * Initialize a new `Hook` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Hook(title, fn) { + Runnable.call(this, title, fn); + this.type = 'hook'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +Hook.prototype = new Runnable; +Hook.prototype.constructor = Hook; + + +}); // module: hook.js + +require.register("interfaces/bdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * BDD-style interface: + * + * describe('Array', function(){ + * describe('#indexOf()', function(){ + * it('should return -1 when not present', function(){ + * + * }); + * + * it('should return the index when present', function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context){ + + // noop variants + + context.xdescribe = function(){}; + context.xit = function(){}; + + /** + * Execute before running tests. + */ + + context.before = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.describe = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn(); + suites.shift(); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.it = function(title, fn){ + suites[0].addTest(new Test(title, fn)); + }; + }); +}; + +}); // module: interfaces/bdd.js + +require.register("interfaces/exports.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * exports.Array = { + * '#indexOf()': { + * 'should return -1 when the value is not present': function(){ + * + * }, + * + * 'should return the correct index when the value is present': function(){ + * + * } + * } + * }; + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('require', visit); + + function visit(obj) { + var suite; + for (var key in obj) { + if ('function' == typeof obj[key]) { + var fn = obj[key]; + switch (key) { + case 'before': + suites[0].beforeAll(fn); + break; + case 'after': + suites[0].afterAll(fn); + break; + case 'beforeEach': + suites[0].beforeEach(fn); + break; + case 'afterEach': + suites[0].afterEach(fn); + break; + default: + suites[0].addTest(new Test(key, fn)); + } + } else { + var suite = Suite.create(suites[0], key); + suites.unshift(suite); + visit(obj[key]); + suites.shift(); + } + } + } +}; +}); // module: interfaces/exports.js + +require.register("interfaces/index.js", function(module, exports, require){ + +exports.bdd = require('./bdd'); +exports.tdd = require('./tdd'); +exports.qunit = require('./qunit'); +exports.exports = require('./exports'); + +}); // module: interfaces/index.js + +require.register("interfaces/qunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * QUnit-style interface: + * + * suite('Array'); + * + * test('#length', function(){ + * var arr = [1,2,3]; + * ok(arr.length == 3); + * }); + * + * test('#indexOf()', function(){ + * var arr = [1,2,3]; + * ok(arr.indexOf(1) == 0); + * ok(arr.indexOf(2) == 1); + * ok(arr.indexOf(3) == 2); + * }); + * + * suite('String'); + * + * test('#length', function(){ + * ok('foo'.length == 3); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context){ + + /** + * Execute before running tests. + */ + + context.before = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Describe a "suite" with the given `title`. + */ + + context.suite = function(title){ + if (suites.length > 1) suites.shift(); + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + suites[0].addTest(new Test(title, fn)); + }; + }); +}; + +}); // module: interfaces/qunit.js + +require.register("interfaces/tdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * suite('Array', function(){ + * suite('#indexOf()', function(){ + * suiteSetup(function(){ + * + * }); + * + * test('should return -1 when not present', function(){ + * + * }); + * + * test('should return the index when present', function(){ + * + * }); + * + * suiteTeardown(function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context){ + + /** + * Execute before each test case. + */ + + context.setup = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.teardown = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Execute before the suite. + */ + + context.suiteSetup = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after the suite. + */ + + context.suiteTeardown = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.suite = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn(); + suites.shift(); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + suites[0].addTest(new Test(title, fn)); + }; + }); +}; + +}); // module: interfaces/tdd.js + +require.register("mocha.js", function(module, exports, require){ + +/*! + * mocha + * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca> + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var path = require('browser/path'); + +/** + * Expose `Mocha`. + */ + +exports = module.exports = Mocha; + +/** + * Library version. + */ + +exports.version = '1.0.3'; + +/** + * Expose internals. + */ + +exports.utils = require('./utils'); +exports.interfaces = require('./interfaces'); +exports.reporters = require('./reporters'); +exports.Runnable = require('./runnable'); +exports.Context = require('./context'); +exports.Runner = require('./runner'); +exports.Suite = require('./suite'); +exports.Hook = require('./hook'); +exports.Test = require('./test'); + +/** + * Return image `name` path. + * + * @param {String} name + * @return {String} + * @api private + */ + +function image(name) { + return __dirname + '/../images/' + name + '.png'; +} + +/** + * Setup mocha with `options`. + * + * Options: + * + * - `ui` name "bdd", "tdd", "exports" etc + * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` + * - `globals` array of accepted globals + * - `timeout` timeout in milliseconds + * - `ignoreLeaks` ignore global leaks + * - `grep` string or regexp to filter tests with + * + * @param {Object} options + * @api public + */ + +function Mocha(options) { + options = options || {}; + options.grep = 'string' == typeof options.grep + ? new RegExp(options.grep) + : options.grep; + this.files = []; + this.options = options; + this.suite = new exports.Suite('', new exports.Context); + this.ui(options.ui); + this.reporter(options.reporter); + if (options.timeout) this.suite.timeout(options.timeout); +} + +/** + * Add test `file`. + * + * @param {String} file + * @api public + */ + +Mocha.prototype.addFile = function(file){ + this.files.push(file); + return this; +}; + +/** + * Set reporter to `name`, defaults to "dot". + * + * @param {String} name + * @api public + */ + +Mocha.prototype.reporter = function(name){ + name = name || 'dot'; + this._reporter = require('./reporters/' + name); + if (!this._reporter) throw new Error('invalid reporter "' + name + '"'); + return this; +}; + +/** + * Set test UI `name`, defaults to "bdd". + * + * @param {String} bdd + * @api public + */ + +Mocha.prototype.ui = function(name){ + name = name || 'bdd'; + this._ui = exports.interfaces[name]; + if (!this._ui) throw new Error('invalid interface "' + name + '"'); + this._ui = this._ui(this.suite); + return this; +}; + +/** + * Load registered files. + * + * @api private + */ + +Mocha.prototype.loadFiles = function(){ + var suite = this.suite; + this.files.forEach(function(file){ + file = path.resolve(file); + suite.emit('pre-require', global, file); + suite.emit('require', require(file), file); + suite.emit('post-require', global, file); + }); +}; + +/** + * Enable growl support. + * + * @api private + */ + +Mocha.prototype.growl = function(runner, reporter) { + var notify = require('growl'); + + runner.on('end', function(){ + var stats = reporter.stats; + if (stats.failures) { + var msg = stats.failures + ' of ' + runner.total + ' tests failed'; + notify(msg, { title: 'Failed', image: image('fail') }); + } else { + notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { + title: 'Passed' + , image: image('pass') + }); + } + }); +}; + +/** + * Add regexp to grep for to the options object + * + * @param {RegExp} or {String} re + * @return {Mocha} + * @api public + */ + +Mocha.prototype.grep = function(re){ + this.options.grep = 'string' == typeof re + ? new RegExp(re) + : re; + return this; +}; + +/** + * Run tests and invoke `fn()` when complete. + * + * @param {Function} fn + * @return {Runner} + * @api public + */ + +Mocha.prototype.run = function(fn){ + this.loadFiles(); + var suite = this.suite; + var options = this.options; + var runner = new exports.Runner(suite); + var reporter = new this._reporter(runner); + runner.ignoreLeaks = options.ignoreLeaks; + if (options.grep) runner.grep(options.grep); + if (options.globals) runner.globals(options.globals); + if (options.growl) this.growl(runner, reporter); + return runner.run(fn); +}; + +}); // module: mocha.js + +require.register("reporters/base.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var tty = require('browser/tty') + , diff = require('browser/diff'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Check if both stdio streams are associated with a tty. + */ + +var isatty = tty.isatty(1) && tty.isatty(2); + +/** + * Expose `Base`. + */ + +exports = module.exports = Base; + +/** + * Enable coloring by default. + */ + +exports.useColors = isatty; + +/** + * Default color map. + */ + +exports.colors = { + 'pass': 90 + , 'fail': 31 + , 'bright pass': 92 + , 'bright fail': 91 + , 'bright yellow': 93 + , 'pending': 36 + , 'suite': 0 + , 'error title': 0 + , 'error message': 31 + , 'error stack': 90 + , 'checkmark': 32 + , 'fast': 90 + , 'medium': 33 + , 'slow': 31 + , 'green': 32 + , 'light': 90 + , 'diff gutter': 90 + , 'diff added': 42 + , 'diff removed': 41 +}; + +/** + * Color `str` with the given `type`, + * allowing colors to be disabled, + * as well as user-defined color + * schemes. + * + * @param {String} type + * @param {String} str + * @return {String} + * @api private + */ + +var color = exports.color = function(type, str) { + if (!exports.useColors) return str; + return '\033[' + exports.colors[type] + 'm' + str + '\033[0m'; +}; + +/** + * Expose term window size, with some + * defaults for when stderr is not a tty. + */ + +exports.window = { + width: isatty + ? process.stdout.getWindowSize + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1] + : 75 +}; + +/** + * Expose some basic cursor interactions + * that are common among reporters. + */ + +exports.cursor = { + hide: function(){ + process.stdout.write('\033[?25l'); + }, + + show: function(){ + process.stdout.write('\033[?25h'); + }, + + deleteLine: function(){ + process.stdout.write('\033[2K'); + }, + + beginningOfLine: function(){ + process.stdout.write('\033[0G'); + }, + + CR: function(){ + exports.cursor.deleteLine(); + exports.cursor.beginningOfLine(); + } +}; + +/** + * A test is considered slow if it + * exceeds the following value in milliseconds. + */ + +exports.slow = 75; + +/** + * Outut the given `failures` as a list. + * + * @param {Array} failures + * @api public + */ + +exports.list = function(failures){ + console.error(); + failures.forEach(function(test, i){ + // format + var fmt = color('error title', ' %s) %s:\n') + + color('error message', ' %s') + + color('error stack', '\n%s\n'); + + // msg + var err = test.err + , message = err.message || '' + , stack = err.stack || message + , index = stack.indexOf(message) + message.length + , msg = stack.slice(0, index) + , actual = err.actual + , expected = err.expected; + + // actual / expected diff + if ('string' == typeof actual && 'string' == typeof expected) { + var len = Math.max(actual.length, expected.length); + + if (len < 20) msg = errorDiff(err, 'Chars'); + else msg = errorDiff(err, 'Words'); + + // linenos + var lines = msg.split('\n'); + if (lines.length > 4) { + var width = String(lines.length).length; + msg = lines.map(function(str, i){ + return pad(++i, width) + ' |' + ' ' + str; + }).join('\n'); + } + + // legend + msg = '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; + + // indent + msg = msg.replace(/^/gm, ' '); + + fmt = color('error title', ' %s) %s:\n%s') + + color('error stack', '\n%s\n'); + } + + // indent stack trace without msg + stack = stack.slice(index ? index + 1 : index) + .replace(/^/gm, ' '); + + console.error(fmt, (i + 1), test.fullTitle(), msg, stack); + }); +}; + +/** + * Initialize a new `Base` reporter. + * + * All other reporters generally + * inherit from this reporter, providing + * stats such as test duration, number + * of tests passed / failed etc. + * + * @param {Runner} runner + * @api public + */ + +function Base(runner) { + var self = this + , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } + , failures = this.failures = []; + + if (!runner) return; + this.runner = runner; + + runner.on('start', function(){ + stats.start = new Date; + }); + + runner.on('suite', function(suite){ + stats.suites = stats.suites || 0; + suite.root || stats.suites++; + }); + + runner.on('test end', function(test){ + stats.tests = stats.tests || 0; + stats.tests++; + }); + + runner.on('pass', function(test){ + stats.passes = stats.passes || 0; + + var medium = exports.slow / 2; + test.speed = test.duration > exports.slow + ? 'slow' + : test.duration > medium + ? 'medium' + : 'fast'; + + stats.passes++; + }); + + runner.on('fail', function(test, err){ + stats.failures = stats.failures || 0; + stats.failures++; + test.err = err; + failures.push(test); + }); + + runner.on('end', function(){ + stats.end = new Date; + stats.duration = new Date - stats.start; + }); + + runner.on('pending', function(){ + stats.pending++; + }); +} + +/** + * Output common epilogue used by many of + * the bundled reporters. + * + * @api public + */ + +Base.prototype.epilogue = function(){ + var stats = this.stats + , fmt + , tests; + + console.log(); + + function pluralize(n) { + return 1 == n ? 'test' : 'tests'; + } + + // failure + if (stats.failures) { + fmt = color('bright fail', ' ✖') + + color('fail', ' %d of %d %s failed') + + color('light', ':') + + console.error(fmt, + stats.failures, + this.runner.total, + pluralize(this.runner.total)); + + Base.list(this.failures); + console.error(); + return; + } + + // pass + fmt = color('bright pass', ' ✔') + + color('green', ' %d %s complete') + + color('light', ' (%dms)'); + + console.log(fmt, + stats.tests || 0, + pluralize(stats.tests), + stats.duration); + + // pending + if (stats.pending) { + fmt = color('pending', ' •') + + color('pending', ' %d %s pending'); + + console.log(fmt, stats.pending, pluralize(stats.pending)); + } + + console.log(); +}; + +/** + * Pad the given `str` to `len`. + * + * @param {String} str + * @param {String} len + * @return {String} + * @api private + */ + +function pad(str, len) { + str = String(str); + return Array(len - str.length + 1).join(' ') + str; +} + +/** + * Return a character diff for `err`. + * + * @param {Error} err + * @return {String} + * @api private + */ + +function errorDiff(err, type) { + return diff['diff' + type](err.actual, err.expected).map(function(str){ + if (/^(\n+)$/.test(str.value)) str.value = Array(++RegExp.$1.length).join('<newline>'); + if (str.added) return colorLines('diff added', str.value); + if (str.removed) return colorLines('diff removed', str.value); + return str.value; + }).join(''); +} + +/** + * Color lines for `str`, using the color `name`. + * + * @param {String} name + * @param {String} str + * @return {String} + * @api private + */ + +function colorLines(name, str) { + return str.split('\n').map(function(str){ + return color(name, str); + }).join('\n'); +} + +}); // module: reporters/base.js + +require.register("reporters/doc.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Doc`. + */ + +exports = module.exports = Doc; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Doc(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , indents = 2; + + function indent() { + return Array(indents).join(' '); + } + + runner.on('suite', function(suite){ + if (suite.root) return; + ++indents; + console.log('%s<section class="suite">', indent()); + ++indents; + console.log('%s<h1>%s</h1>', indent(), suite.title); + console.log('%s<dl>', indent()); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + console.log('%s</dl>', indent()); + --indents; + console.log('%s</section>', indent()); + --indents; + }); + + runner.on('pass', function(test){ + console.log('%s <dt>%s</dt>', indent(), test.title); + var code = utils.escape(clean(test.fn.toString())); + console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code); + }); +} + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +function clean(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , re = new RegExp('^ {' + spaces + '}', 'gm'); + + str = str.replace(re, ''); + + return str; +} +}); // module: reporters/doc.js + +require.register("reporters/dot.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = Dot; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Dot(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , n = 0; + + runner.on('start', function(){ + process.stdout.write('\n '); + }); + + runner.on('pending', function(test){ + process.stdout.write(color('pending', '.')); + }); + + runner.on('pass', function(test){ + if (++n % width == 0) process.stdout.write('\n '); + if ('slow' == test.speed) { + process.stdout.write(color('bright yellow', '.')); + } else { + process.stdout.write(color(test.speed, '.')); + } + }); + + runner.on('fail', function(test, err){ + if (++n % width == 0) process.stdout.write('\n '); + process.stdout.write(color('fail', '.')); + }); + + runner.on('end', function(){ + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +Dot.prototype = new Base; +Dot.prototype.constructor = Dot; + +}); // module: reporters/dot.js + +require.register("reporters/html-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var JSONCov = require('./json-cov') + , fs = require('browser/fs'); + +/** + * Expose `HTMLCov`. + */ + +exports = module.exports = HTMLCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTMLCov(runner) { + var jade = require('jade') + , file = __dirname + '/templates/coverage.jade' + , str = fs.readFileSync(file, 'utf8') + , fn = jade.compile(str, { filename: file }) + , self = this; + + JSONCov.call(this, runner, false); + + runner.on('end', function(){ + process.stdout.write(fn({ + cov: self.cov + , coverageClass: coverageClass + })); + }); +} + +function coverageClass(n) { + if (n >= 75) return 'high'; + if (n >= 50) return 'medium'; + if (n >= 25) return 'low'; + return 'terrible'; +} +}); // module: reporters/html-cov.js + +require.register("reporters/html.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , Progress = require('../browser/progress') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `Doc`. + */ + +exports = module.exports = HTML; + +/** + * Stats template. + */ + +var statsTemplate = '<ul id="stats">' + + '<li class="progress"><canvas width="40" height="40"></canvas></li>' + + '<li class="passes">passes: <em>0</em></li>' + + '<li class="failures">failures: <em>0</em></li>' + + '<li class="duration">duration: <em>0</em>s</li>' + + '</ul>'; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTML(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , root = document.getElementById('mocha') + , stat = fragment(statsTemplate) + , items = stat.getElementsByTagName('li') + , passes = items[1].getElementsByTagName('em')[0] + , failures = items[2].getElementsByTagName('em')[0] + , duration = items[3].getElementsByTagName('em')[0] + , canvas = stat.getElementsByTagName('canvas')[0] + , stack = [root] + , progress + , ctx + + if (canvas.getContext) { + ctx = canvas.getContext('2d'); + progress = new Progress; + } + + if (!root) return error('#mocha div missing, add it to your document'); + + root.appendChild(stat); + + if (progress) progress.size(40); + + runner.on('suite', function(suite){ + if (suite.root) return; + + // suite + var el = fragment('<div class="suite"><h1>%s</h1></div>', suite.title); + + // container + stack[0].appendChild(el); + stack.unshift(document.createElement('div')); + el.appendChild(stack[0]); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + stack.shift(); + }); + + runner.on('fail', function(test, err){ + if ('hook' == test.type || err.uncaught) runner.emit('test end', test); + }); + + runner.on('test end', function(test){ + // TODO: add to stats + var percent = stats.tests / total * 100 | 0; + if (progress) progress.update(percent).draw(ctx); + + // update stats + var ms = new Date - stats.start; + text(passes, stats.passes); + text(failures, stats.failures); + text(duration, (ms / 1000).toFixed(2)); + + // test + if ('passed' == test.state) { + var el = fragment('<div class="test pass %e"><h2>%e<span class="duration">%ems</span></h2></div>', test.speed, test.title, test.duration); + } else if (test.pending) { + var el = fragment('<div class="test pass pending"><h2>%e</h2></div>', test.title); + } else { + var el = fragment('<div class="test fail"><h2>%e</h2></div>', test.title); + var str = test.err.stack || test.err.toString(); + + // FF / Opera do not add the message + if (!~str.indexOf(test.err.message)) { + str = test.err.message + '\n' + str; + } + + // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we + // check for the result of the stringifying. + if ('[object Error]' == str) str = test.err.message; + + // Safari doesn't give you a stack. Let's at least provide a source line. + if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { + str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; + } + + el.appendChild(fragment('<pre class="error">%e</pre>', str)); + } + + // toggle code + var h2 = el.getElementsByTagName('h2')[0]; + + on(h2, 'click', function(){ + pre.style.display = 'none' == pre.style.display + ? 'block' + : 'none'; + }); + + // code + // TODO: defer + if (!test.pending) { + var pre = fragment('<pre><code>%e</code></pre>', clean(test.fn.toString())); + el.appendChild(pre); + pre.style.display = 'none'; + } + + stack[0].appendChild(el); + }); +} + +/** + * Display error `msg`. + */ + +function error(msg) { + document.body.appendChild(fragment('<div id="error">%s</div>', msg)); +} + +/** + * Return a DOM fragment from `html`. + */ + +function fragment(html) { + var args = arguments + , div = document.createElement('div') + , i = 1; + + div.innerHTML = html.replace(/%([se])/g, function(_, type){ + switch (type) { + case 's': return String(args[i++]); + case 'e': return escape(args[i++]); + } + }); + + return div.firstChild; +} + +/** + * Set `el` text to `str`. + */ + +function text(el, str) { + if (el.textContent) { + el.textContent = str; + } else { + el.innerText = str; + } +} + +/** + * Listen on `event` with callback `fn`. + */ + +function on(el, event, fn) { + if (el.addEventListener) { + el.addEventListener(event, fn, false); + } else { + el.attachEvent('on' + event, fn); + } +} + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +function clean(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , re = new RegExp('^ {' + spaces + '}', 'gm'); + + str = str + .replace(re, '') + .replace(/^\s+/, ''); + + return str; +} + +}); // module: reporters/html.js + +require.register("reporters/index.js", function(module, exports, require){ + +exports.Base = require('./base'); +exports.Dot = require('./dot'); +exports.Doc = require('./doc'); +exports.TAP = require('./tap'); +exports.JSON = require('./json'); +exports.HTML = require('./html'); +exports.List = require('./list'); +exports.Min = require('./min'); +exports.Spec = require('./spec'); +exports.Progress = require('./progress'); +exports.Landing = require('./landing'); +exports.JSONCov = require('./json-cov'); +exports.HTMLCov = require('./html-cov'); +exports.JSONStream = require('./json-stream'); +exports.XUnit = require('./xunit') +exports.Teamcity = require('./teamcity') + +}); // module: reporters/index.js + +require.register("reporters/json-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `JSONCov`. + */ + +exports = module.exports = JSONCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @param {Boolean} output + * @api public + */ + +function JSONCov(runner, output) { + var self = this + , output = 1 == arguments.length ? true : output; + + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var cov = global._$jscoverage || {}; + var result = self.cov = map(cov); + result.stats = self.stats; + result.tests = tests.map(clean); + result.failures = failures.map(clean); + result.passes = passes.map(clean); + if (!output) return; + process.stdout.write(JSON.stringify(result, null, 2 )); + }); +} + +/** + * Map jscoverage data to a JSON structure + * suitable for reporting. + * + * @param {Object} cov + * @return {Object} + * @api private + */ + +function map(cov) { + var ret = { + instrumentation: 'node-jscoverage' + , sloc: 0 + , hits: 0 + , misses: 0 + , coverage: 0 + , files: [] + }; + + for (var filename in cov) { + var data = coverage(filename, cov[filename]); + ret.files.push(data); + ret.hits += data.hits; + ret.misses += data.misses; + ret.sloc += data.sloc; + } + + if (ret.sloc > 0) { + ret.coverage = (ret.hits / ret.sloc) * 100; + } + + return ret; +}; + +/** + * Map jscoverage data for a single source file + * to a JSON structure suitable for reporting. + * + * @param {String} filename name of the source file + * @param {Object} data jscoverage coverage data + * @return {Object} + * @api private + */ + +function coverage(filename, data) { + var ret = { + filename: filename, + coverage: 0, + hits: 0, + misses: 0, + sloc: 0, + source: {} + }; + + data.source.forEach(function(line, num){ + num++; + + if (data[num] === 0) { + ret.misses++; + ret.sloc++; + } else if (data[num] !== undefined) { + ret.hits++; + ret.sloc++; + } + + ret.source[num] = { + source: line + , coverage: data[num] === undefined + ? '' + : data[num] + }; + }); + + ret.coverage = ret.hits / ret.sloc * 100; + + return ret; +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} + +}); // module: reporters/json-cov.js + +require.register("reporters/json-stream.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total; + + runner.on('start', function(){ + console.log(JSON.stringify(['start', { total: total }])); + }); + + runner.on('pass', function(test){ + console.log(JSON.stringify(['pass', clean(test)])); + }); + + runner.on('fail', function(test, err){ + console.log(JSON.stringify(['fail', clean(test)])); + }); + + runner.on('end', function(){ + process.stdout.write(JSON.stringify(['end', self.stats])); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json-stream.js + +require.register("reporters/json.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `JSON`. + */ + +exports = module.exports = JSONReporter; + +/** + * Initialize a new `JSON` reporter. + * + * @param {Runner} runner + * @api public + */ + +function JSONReporter(runner) { + var self = this; + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var obj = { + stats: self.stats + , tests: tests.map(clean) + , failures: failures.map(clean) + , passes: passes.map(clean) + }; + + process.stdout.write(JSON.stringify(obj, null, 2)); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json.js + +require.register("reporters/landing.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Landing`. + */ + +exports = module.exports = Landing; + +/** + * Airplane color. + */ + +Base.colors.plane = 0; + +/** + * Airplane crash color. + */ + +Base.colors['plane crash'] = 31; + +/** + * Runway color. + */ + +Base.colors.runway = 90; + +/** + * Initialize a new `Landing` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Landing(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , total = runner.total + , stream = process.stdout + , plane = color('plane', '✈') + , crashed = -1 + , n = 0; + + function runway() { + var buf = Array(width).join('-'); + return ' ' + color('runway', buf); + } + + runner.on('start', function(){ + stream.write('\n '); + cursor.hide(); + }); + + runner.on('test end', function(test){ + // check if the plane crashed + var col = -1 == crashed + ? width * ++n / total | 0 + : crashed; + + // show the crash + if ('failed' == test.state) { + plane = color('plane crash', '✈'); + crashed = col; + } + + // render landing strip + stream.write('\033[4F\n\n'); + stream.write(runway()); + stream.write('\n '); + stream.write(color('runway', Array(col).join('⋅'))); + stream.write(plane) + stream.write(color('runway', Array(width - col).join('⋅') + '\n')); + stream.write(runway()); + stream.write('\033[0m'); + }); + + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +Landing.prototype = new Base; +Landing.prototype.constructor = Landing; + +}); // module: reporters/landing.js + +require.register("reporters/list.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 0; + + runner.on('start', function(){ + console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = color('checkmark', ' -') + + color('pending', ' %s'); + console.log(fmt, test.fullTitle()); + }); + + runner.on('pass', function(test){ + var fmt = color('checkmark', ' ✓') + + color('pass', ' %s: ') + + color(test.speed, '%dms'); + cursor.CR(); + console.log(fmt, test.fullTitle(), test.duration); + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +List.prototype = new Base; +List.prototype.constructor = List; + + +}); // module: reporters/list.js + +require.register("reporters/markdown.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Markdown`. + */ + +exports = module.exports = Markdown; + +/** + * Initialize a new `Markdown` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Markdown(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , level = 0 + , buf = ''; + + function title(str) { + return Array(level).join('#') + ' ' + str; + } + + function indent() { + return Array(level).join(' '); + } + + function mapTOC(suite, obj) { + var ret = obj; + obj = obj[suite.title] = obj[suite.title] || { suite: suite }; + suite.suites.forEach(function(suite){ + mapTOC(suite, obj); + }); + return ret; + } + + function stringifyTOC(obj, level) { + ++level; + var buf = ''; + var link; + for (var key in obj) { + if ('suite' == key) continue; + if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; + if (key) buf += Array(level).join(' ') + link; + buf += stringifyTOC(obj[key], level); + } + --level; + return buf; + } + + function generateTOC(suite) { + var obj = mapTOC(suite, {}); + return stringifyTOC(obj, 0); + } + + generateTOC(runner.suite); + + runner.on('suite', function(suite){ + ++level; + var slug = utils.slug(suite.fullTitle()); + buf += '<a name="' + slug + '" />' + '\n'; + buf += title(suite.title) + '\n'; + }); + + runner.on('suite end', function(suite){ + --level; + }); + + runner.on('pass', function(test){ + var code = clean(test.fn.toString()); + buf += test.title + '.\n'; + buf += '\n```js'; + buf += code + '\n'; + buf += '```\n\n'; + }); + + runner.on('end', function(){ + process.stdout.write('# TOC\n'); + process.stdout.write(generateTOC(runner.suite)); + process.stdout.write(buf); + }); +} + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +function clean(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , re = new RegExp('^ {' + spaces + '}', 'gm'); + + str = str.replace(re, ''); + + return str; +} +}); // module: reporters/markdown.js + +require.register("reporters/min.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Min`. + */ + +exports = module.exports = Min; + +/** + * Initialize a new `Min` minimal test reporter (best used with --watch). + * + * @param {Runner} runner + * @api public + */ + +function Min(runner) { + Base.call(this, runner); + + runner.on('start', function(){ + // clear screen + process.stdout.write('\033[2J'); + // set cursor position + process.stdout.write('\033[1;3H'); + }); + + runner.on('end', this.epilogue.bind(this)); +} + +/** + * Inherit from `Base.prototype`. + */ + +Min.prototype = new Base; +Min.prototype.constructor = Min; + +}); // module: reporters/min.js + +require.register("reporters/progress.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Progress`. + */ + +exports = module.exports = Progress; + +/** + * General progress bar color. + */ + +Base.colors.progress = 90; + +/** + * Initialize a new `Progress` bar test reporter. + * + * @param {Runner} runner + * @param {Object} options + * @api public + */ + +function Progress(runner, options) { + Base.call(this, runner); + + var self = this + , options = options || {} + , stats = this.stats + , width = Base.window.width * .50 | 0 + , total = runner.total + , complete = 0 + , max = Math.max; + + // default chars + options.open = options.open || '['; + options.complete = options.complete || '▬'; + options.incomplete = options.incomplete || '⋅'; + options.close = options.close || ']'; + options.verbose = false; + + // tests started + runner.on('start', function(){ + console.log(); + cursor.hide(); + }); + + // tests complete + runner.on('test end', function(){ + complete++; + var incomplete = total - complete + , percent = complete / total + , n = width * percent | 0 + , i = width - n; + + cursor.CR(); + process.stdout.write('\033[J'); + process.stdout.write(color('progress', ' ' + options.open)); + process.stdout.write(Array(n).join(options.complete)); + process.stdout.write(Array(i).join(options.incomplete)); + process.stdout.write(color('progress', options.close)); + if (options.verbose) { + process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); + } + }); + + // tests are complete, output some stats + // and the failures if any + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +Progress.prototype = new Base; +Progress.prototype.constructor = Progress; + + +}); // module: reporters/progress.js + +require.register("reporters/spec.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Spec`. + */ + +exports = module.exports = Spec; + +/** + * Initialize a new `Spec` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Spec(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , indents = 0 + , n = 0; + + function indent() { + return Array(indents).join(' ') + } + + runner.on('start', function(){ + console.log(); + }); + + runner.on('suite', function(suite){ + ++indents; + console.log(color('suite', '%s%s'), indent(), suite.title); + }); + + runner.on('suite end', function(suite){ + --indents; + if (1 == indents) console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = indent() + color('pending', ' - %s'); + console.log(fmt, test.title); + }); + + runner.on('pass', function(test){ + if ('fast' == test.speed) { + var fmt = indent() + + color('checkmark', ' ✓') + + color('pass', ' %s '); + cursor.CR(); + console.log(fmt, test.title); + } else { + var fmt = indent() + + color('checkmark', ' ✓') + + color('pass', ' %s ') + + color(test.speed, '(%dms)'); + cursor.CR(); + console.log(fmt, test.title, test.duration); + } + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +Spec.prototype = new Base; +Spec.prototype.constructor = Spec; + + +}); // module: reporters/spec.js + +require.register("reporters/tap.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `TAP`. + */ + +exports = module.exports = TAP; + +/** + * Initialize a new `TAP` reporter. + * + * @param {Runner} runner + * @api public + */ + +function TAP(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , n = 1; + + runner.on('start', function(){ + console.log('%d..%d', 1, total); + }); + + runner.on('test end', function(){ + ++n; + }); + + runner.on('pending', function(test){ + console.log('ok %d %s # SKIP -', n, title(test)); + }); + + runner.on('pass', function(test){ + console.log('ok %d %s', n, title(test)); + }); + + runner.on('fail', function(test, err){ + console.log('not ok %d %s', n, title(test)); + console.log(err.stack.replace(/^/gm, ' ')); + }); +} + +/** + * Return a TAP-safe title of `test` + * + * @param {Object} test + * @return {String} + * @api private + */ + +function title(test) { + return test.fullTitle().replace(/#/g, ''); +} + +}); // module: reporters/tap.js + +require.register("reporters/teamcity.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Teamcity`. + */ + +exports = module.exports = Teamcity; + +/** + * Initialize a new `Teamcity` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Teamcity(runner) { + Base.call(this, runner); + var stats = this.stats; + + runner.on('start', function() { + console.log("##teamcity[testSuiteStarted name='mocha.suite']"); + }); + + runner.on('test', function(test) { + console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']"); + }); + + runner.on('fail', function(test, err) { + console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']"); + }); + + runner.on('pending', function(test) { + console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']"); + }); + + runner.on('test end', function(test) { + console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']"); + }); + + runner.on('end', function() { + console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']"); + }); +} + +/** + * Escape the given `str`. + */ + +function escape(str) { + return str.replace(/'/g, "|'"); +} +}); // module: reporters/teamcity.js + +require.register("reporters/xunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `XUnit`. + */ + +exports = module.exports = XUnit; + +/** + * Initialize a new `XUnit` reporter. + * + * @param {Runner} runner + * @api public + */ + +function XUnit(runner) { + Base.call(this, runner); + var stats = this.stats + , tests = [] + , self = this; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('end', function(){ + console.log(tag('testsuite', { + name: 'Mocha Tests' + , tests: stats.tests + , failures: stats.failures + , errors: stats.failures + , skip: stats.tests - stats.failures - stats.passes + , timestamp: (new Date).toUTCString() + , time: stats.duration / 1000 + }, false)); + + tests.forEach(test); + console.log('</testsuite>'); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +XUnit.prototype = new Base; +XUnit.prototype.constructor = XUnit; + + +/** + * Output tag for the given `test.` + */ + +function test(test) { + var attrs = { + classname: test.parent.fullTitle() + , name: test.title + , time: test.duration / 1000 + }; + + if ('failed' == test.state) { + var err = test.err; + attrs.message = escape(err.message); + console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); + } else if (test.pending) { + console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); + } else { + console.log(tag('testcase', attrs, true) ); + } +} + +/** + * HTML tag helper. + */ + +function tag(name, attrs, close, content) { + var end = close ? '/>' : '>' + , pairs = [] + , tag; + + for (var key in attrs) { + pairs.push(key + '="' + escape(attrs[key]) + '"'); + } + + tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; + if (content) tag += content + '</' + name + end; + return tag; +} + +/** + * Return cdata escaped CDATA `str`. + */ + +function cdata(str) { + return '<![CDATA[' + escape(str) + ']]>'; +} + +}); // module: reporters/xunit.js + +require.register("runnable.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('runnable'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `Runnable`. + */ + +module.exports = Runnable; + +/** + * Initialize a new `Runnable` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Runnable(title, fn) { + this.title = title; + this.fn = fn; + this.async = fn && fn.length; + this.sync = ! this.async; + this._timeout = 2000; + this.timedOut = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Runnable.prototype = new EventEmitter; +Runnable.prototype.constructor = Runnable; + + +/** + * Set & get timeout `ms`. + * + * @param {Number} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + debug('timeout %d', ms); + this._timeout = ms; + if (this.timer) this.resetTimeout(); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Runnable.prototype.fullTitle = function(){ + return this.parent.fullTitle() + ' ' + this.title; +}; + +/** + * Clear the timeout. + * + * @api private + */ + +Runnable.prototype.clearTimeout = function(){ + clearTimeout(this.timer); +}; + +/** + * Reset the timeout. + * + * @api private + */ + +Runnable.prototype.resetTimeout = function(){ + var self = this + , ms = this.timeout(); + + this.clearTimeout(); + if (ms) { + this.timer = setTimeout(function(){ + self.callback(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); + } +}; + +/** + * Run the test and invoke `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runnable.prototype.run = function(fn){ + var self = this + , ms = this.timeout() + , start = new Date + , ctx = this.ctx + , finished + , emitted; + + if (ctx) ctx.runnable(this); + + // timeout + if (this.async) { + if (ms) { + this.timer = setTimeout(function(){ + done(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); + } + } + + // called multiple times + function multiple() { + if (emitted) return; + emitted = true; + self.emit('error', new Error('done() called multiple times')); + } + + // finished + function done(err) { + if (self.timedOut) return; + if (finished) return multiple(); + self.clearTimeout(); + self.duration = new Date - start; + finished = true; + fn(err); + } + + // for .resetTimeout() + this.callback = done; + + // async + if (this.async) { + try { + this.fn.call(ctx, function(err){ + if (err instanceof Error) return done(err); + if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); + done(); + }); + } catch (err) { + done(err); + } + return; + } + + // sync + try { + if (!this.pending) this.fn.call(ctx); + this.duration = new Date - start; + fn(); + } catch (err) { + fn(err); + } +}; + +}); // module: runnable.js + +require.register("runner.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('runner') + , Test = require('./test') + , utils = require('./utils') + , noop = function(){}; + +/** + * Expose `Runner`. + */ + +module.exports = Runner; + +/** + * Initialize a `Runner` for the given `suite`. + * + * Events: + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * + * @api public + */ + +function Runner(suite) { + var self = this; + this._globals = []; + this.suite = suite; + this.total = suite.total(); + this.failures = 0; + this.on('test end', function(test){ self.checkGlobals(test); }); + this.on('hook end', function(hook){ self.checkGlobals(hook); }); + this.grep(/.*/); + this.globals(utils.keys(global).concat(['errno'])); +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Runner.prototype = new EventEmitter; +Runner.prototype.constructor = Runner; + + +/** + * Run tests with full titles matching `re`. Updates runner.total + * with number of tests matched. + * + * @param {RegExp} re + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.grep = function(re){ + debug('grep %s', re); + this._grep = re; + this.total = this.grepTotal(this.suite); + return this; +}; + +/** + * Returns the number of tests matching the grep search for the + * given suite. + * + * @param {Suite} suite + * @return {Number} + * @api public + */ + +Runner.prototype.grepTotal = function(suite) { + var self = this; + var total = 0; + + suite.eachTest(function(test){ + if (self._grep.test(test.fullTitle())) total++; + }); + + return total; +}; + +/** + * Allow the given `arr` of globals. + * + * @param {Array} arr + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.globals = function(arr){ + if (0 == arguments.length) return this._globals; + debug('globals %j', arr); + utils.forEach(arr, function(arr){ + this._globals.push(arr); + }, this); + return this; +}; + +/** + * Check for global variable leaks. + * + * @api private + */ + +Runner.prototype.checkGlobals = function(test){ + if (this.ignoreLeaks) return; + + var leaks = utils.filter(utils.keys(global), function(key){ + return !~utils.indexOf(this._globals, key) && (!global.navigator || 'onerror' !== key); + }, this); + + this._globals = this._globals.concat(leaks); + + if (leaks.length > 1) { + this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); + } else if (leaks.length) { + this.fail(test, new Error('global leak detected: ' + leaks[0])); + } +}; + +/** + * Fail the given `test`. + * + * @param {Test} test + * @param {Error} err + * @api private + */ + +Runner.prototype.fail = function(test, err){ + ++this.failures; + test.state = 'failed'; + if ('string' == typeof err) { + err = new Error('the string "' + err + '" was thrown, throw an Error :)'); + } + this.emit('fail', test, err); +}; + +/** + * Fail the given `hook` with `err`. + * + * Hook failures (currently) hard-end due + * to that fact that a failing hook will + * surely cause subsequent tests to fail, + * causing jumbled reporting. + * + * @param {Hook} hook + * @param {Error} err + * @api private + */ + +Runner.prototype.failHook = function(hook, err){ + this.fail(hook, err); + this.emit('end'); +}; + +/** + * Run hook `name` callbacks and then invoke `fn()`. + * + * @param {String} name + * @param {Function} function + * @api private + */ + +Runner.prototype.hook = function(name, fn){ + var suite = this.suite + , hooks = suite['_' + name] + , ms = suite._timeout + , self = this + , timer; + + function next(i) { + var hook = hooks[i]; + if (!hook) return fn(); + self.currentRunnable = hook; + + self.emit('hook', hook); + + hook.on('error', function(err){ + self.failHook(hook, err); + }); + + hook.run(function(err){ + hook.removeAllListeners('error'); + if (err) return self.failHook(hook, err); + self.emit('hook end', hook); + next(++i); + }); + } + + process.nextTick(function(){ + next(0); + }); +}; + +/** + * Run hook `name` for the given array of `suites` + * in order, and callback `fn(err)`. + * + * @param {String} name + * @param {Array} suites + * @param {Function} fn + * @api private + */ + +Runner.prototype.hooks = function(name, suites, fn){ + var self = this + , orig = this.suite; + + function next(suite) { + self.suite = suite; + + if (!suite) { + self.suite = orig; + return fn(); + } + + self.hook(name, function(err){ + if (err) { + self.suite = orig; + return fn(err); + } + + next(suites.pop()); + }); + } + + next(suites.pop()); +}; + +/** + * Run hooks from the top level down. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookUp = function(name, fn){ + var suites = [this.suite].concat(this.parents()).reverse(); + this.hooks(name, suites, fn); +}; + +/** + * Run hooks from the bottom up. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookDown = function(name, fn){ + var suites = [this.suite].concat(this.parents()); + this.hooks(name, suites, fn); +}; + +/** + * Return an array of parent Suites from + * closest to furthest. + * + * @return {Array} + * @api private + */ + +Runner.prototype.parents = function(){ + var suite = this.suite + , suites = []; + while (suite = suite.parent) suites.push(suite); + return suites; +}; + +/** + * Run the current test and callback `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTest = function(fn){ + var test = this.test + , self = this; + + try { + test.on('error', function(err){ + self.fail(test, err); + }); + test.run(fn); + } catch (err) { + fn(err); + } +}; + +/** + * Run tests in the given `suite` and invoke + * the callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTests = function(suite, fn){ + var self = this + , tests = suite.tests + , test; + + function next(err) { + // if we bail after first err + if (self.failures && suite._bail) return fn(); + + // next test + test = tests.shift(); + + // all done + if (!test) return fn(); + + // grep + if (!self._grep.test(test.fullTitle())) return next(); + + // pending + if (test.pending) { + self.emit('pending', test); + self.emit('test end', test); + return next(); + } + + // execute test and hook(s) + self.emit('test', self.test = test); + self.hookDown('beforeEach', function(){ + self.currentRunnable = self.test; + self.runTest(function(err){ + test = self.test; + + if (err) { + self.fail(test, err); + self.emit('test end', test); + return self.hookUp('afterEach', next); + } + + test.state = 'passed'; + self.emit('pass', test); + self.emit('test end', test); + self.hookUp('afterEach', next); + }); + }); + } + + this.next = next; + next(); +}; + +/** + * Run the given `suite` and invoke the + * callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runSuite = function(suite, fn){ + var total = this.grepTotal(suite) + , self = this + , i = 0; + + debug('run suite %s', suite.fullTitle()); + + if (!total) return fn(); + + this.emit('suite', this.suite = suite); + + function next() { + var curr = suite.suites[i++]; + if (!curr) return done(); + self.runSuite(curr, next); + } + + function done() { + self.suite = suite; + self.hook('afterAll', function(){ + self.emit('suite end', suite); + fn(); + }); + } + + this.hook('beforeAll', function(){ + self.runTests(suite, next); + }); +}; + +/** + * Handle uncaught exceptions. + * + * @param {Error} err + * @api private + */ + +Runner.prototype.uncaught = function(err){ + debug('uncaught exception'); + var runnable = this.currentRunnable; + if ('failed' == runnable.state) return; + runnable.clearTimeout(); + err.uncaught = true; + this.fail(runnable, err); + + // recover from test + if ('test' == runnable.type) { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } + + // bail on hooks + this.emit('end'); +}; + +/** + * Run the root suite and invoke `fn(failures)` + * on completion. + * + * @param {Function} fn + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.run = function(fn){ + var self = this + , fn = fn || function(){}; + + debug('start'); + + // callback + this.on('end', function(){ + debug('end'); + process.removeListener('uncaughtException', this.uncaught); + fn(self.failures); + }); + + // run suites + this.emit('start'); + this.runSuite(this.suite, function(){ + debug('finished running'); + self.emit('end'); + }); + + // uncaught exception + process.on('uncaughtException', function(err){ + self.uncaught(err); + }); + + return this; +}; + +}); // module: runner.js + +require.register("suite.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('suite') + , utils = require('./utils') + , Hook = require('./hook'); + +/** + * Expose `Suite`. + */ + +exports = module.exports = Suite; + +/** + * Create a new `Suite` with the given `title` + * and parent `Suite`. When a suite with the + * same title is already present, that suite + * is returned to provide nicer reporter + * and more flexible meta-testing. + * + * @param {Suite} parent + * @param {String} title + * @return {Suite} + * @api public + */ + +exports.create = function(parent, title){ + var suite = new Suite(title, parent.ctx); + suite.parent = parent; + title = suite.fullTitle(); + parent.addSuite(suite); + return suite; +}; + +/** + * Initialize a new `Suite` with the given + * `title` and `ctx`. + * + * @param {String} title + * @param {Context} ctx + * @api private + */ + +function Suite(title, ctx) { + this.title = title; + this.ctx = ctx; + this.suites = []; + this.tests = []; + this._beforeEach = []; + this._beforeAll = []; + this._afterEach = []; + this._afterAll = []; + this.root = !title; + this._timeout = 2000; + this._bail = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Suite.prototype = new EventEmitter; +Suite.prototype.constructor = Suite; + + +/** + * Return a clone of this `Suite`. + * + * @return {Suite} + * @api private + */ + +Suite.prototype.clone = function(){ + var suite = new Suite(this.title); + debug('clone'); + suite.ctx = this.ctx; + suite.timeout(this.timeout()); + suite.bail(this.bail()); + return suite; +}; + +/** + * Set timeout `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if (String(ms).match(/s$/)) ms = parseFloat(ms) * 1000; + debug('timeout %d', ms); + this._timeout = parseInt(ms, 10); + return this; +}; + +/** + * Sets whether to bail after first error. + * + * @parma {Boolean} bail + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.bail = function(bail){ + if (0 == arguments.length) return this._bail; + debug('bail %s', bail); + this._bail = bail; + return this; +}; + +/** + * Run `fn(test[, done])` before running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeAll = function(fn){ + var hook = new Hook('"before all" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.ctx = this.ctx; + this._beforeAll.push(hook); + this.emit('beforeAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterAll = function(fn){ + var hook = new Hook('"after all" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.ctx = this.ctx; + this._afterAll.push(hook); + this.emit('afterAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` before each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeEach = function(fn){ + var hook = new Hook('"before each" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.ctx = this.ctx; + this._beforeEach.push(hook); + this.emit('beforeEach', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterEach = function(fn){ + var hook = new Hook('"after each" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.ctx = this.ctx; + this._afterEach.push(hook); + this.emit('afterEach', hook); + return this; +}; + +/** + * Add a test `suite`. + * + * @param {Suite} suite + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addSuite = function(suite){ + suite.parent = this; + suite.timeout(this.timeout()); + suite.bail(this.bail()); + this.suites.push(suite); + this.emit('suite', suite); + return this; +}; + +/** + * Add a `test` to this suite. + * + * @param {Test} test + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addTest = function(test){ + test.parent = this; + test.timeout(this.timeout()); + test.ctx = this.ctx; + this.tests.push(test); + this.emit('test', test); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Suite.prototype.fullTitle = function(){ + if (this.parent) { + var full = this.parent.fullTitle(); + if (full) return full + ' ' + this.title; + } + return this.title; +}; + +/** + * Return the total number of tests. + * + * @return {Number} + * @api public + */ + +Suite.prototype.total = function(){ + return utils.reduce(this.suites, function(sum, suite){ + return sum + suite.total(); + }, 0) + this.tests.length; +}; + +/** + * Iterates through each suite recursively to find + * all tests. Applies a function in the format + * `fn(test)`. + * + * @param {Function} fn + * @return {Suite} + * @api private + */ + +Suite.prototype.eachTest = function(fn){ + utils.forEach(this.tests, fn); + utils.forEach(this.suites, function(suite){ + suite.eachTest(fn); + }); + return this; +}; + +}); // module: suite.js + +require.register("test.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Test`. + */ + +module.exports = Test; + +/** + * Initialize a new `Test` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Test(title, fn) { + Runnable.call(this, title, fn); + this.pending = !fn; + this.type = 'test'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +Test.prototype = new Runnable; +Test.prototype.constructor = Test; + + +/** + * Inspect the context void of private properties. + * + * @return {String} + * @api private + */ + +Test.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + return '_' == key[0] + ? undefined + : 'parent' == key + ? '#<Suite>' + : val; + }, 2); +}; +}); // module: test.js + +require.register("utils.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var fs = require('browser/fs') + , path = require('browser/path') + , join = path.join + , debug = require('browser/debug')('watch'); + +/** + * Ignored directories. + */ + +var ignore = ['node_modules', '.git']; + +/** + * Escape special characters in the given string of html. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html) { + return String(html) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/</g, '<') + .replace(/>/g, '>'); +}; + +/** + * Array#forEach (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.forEach = function(arr, fn, scope) { + for (var i = 0, l = arr.length; i < l; i++) + fn.call(scope, arr[i], i); +}; + +/** + * Array#indexOf (<=IE8) + * + * @parma {Array} arr + * @param {Object} obj to find index of + * @param {Number} start + * @api private + */ + +exports.indexOf = function (arr, obj, start) { + for (var i = start || 0, l = arr.length; i < l; i++) { + if (arr[i] === obj) + return i; + } + return -1; +}; + +/** + * Array#reduce (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} initial value + * @param {Object} scope + * @api private + */ + +exports.reduce = function(arr, fn, val, scope) { + var rval = val; + + for (var i = 0, l = arr.length; i < l; i++) { + rval = fn.call(scope, rval, arr[i], i, arr); + } + + return rval; +}; + +/** + * Array#filter (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.filter = function(arr, fn, scope) { + var ret = []; + + for (var i = 0, l = arr.length; i < l; i++) { + var val = arr[i]; + if (fn.call(scope, val, i, arr)) + ret.push(val); + } + + return ret; +}; + +/** + * Object.keys (<=IE8) + * + * @param {Object} obj + * @return {Array} keys + * @api private + */ + +exports.keys = Object.keys || function(obj) { + var keys = [] + , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 + + for (var key in obj) { + if (has.call(obj, key)) { + keys.push(key); + } + } + + return keys; +}; + +/** + * Watch the given `files` for changes + * and invoke `fn(file)` on modification. + * + * @param {Array} files + * @param {Function} fn + * @api private + */ + +exports.watch = function(files, fn){ + var options = { interval: 100 }; + files.forEach(function(file){ + debug('file %s', file); + fs.watchFile(file, options, function(curr, prev){ + if (prev.mtime < curr.mtime) fn(file); + }); + }); +}; + +/** + * Ignored files. + */ + +function ignored(path){ + return !~ignore.indexOf(path); +} + +/** + * Lookup files in the given `dir`. + * + * @return {Array} + * @api private + */ + +exports.files = function(dir, ret){ + ret = ret || []; + + fs.readdirSync(dir) + .filter(ignored) + .forEach(function(path){ + path = join(dir, path); + if (fs.statSync(path).isDirectory()) { + exports.files(path, ret); + } else if (path.match(/\.(js|coffee)$/)) { + ret.push(path); + } + }); + + return ret; +}; + +/** + * Compute a slug from the given `str`. + * + * @param {String} str + * @return {String} + */ + +exports.slug = function(str){ + return str + .toLowerCase() + .replace(/ +/g, '-') + .replace(/[^-\w]/g, ''); +}; +}); // module: utils.js +/** + * Node shims. + * + * These are meant only to allow + * mocha.js to run untouched, not + * to allow running node code in + * the browser. + */ + +process = {}; +process.exit = function(status){}; +process.stdout = {}; +global = window; + +/** + * next tick implementation. + */ + +process.nextTick = (function(){ + // postMessage behaves badly on IE8 + if (window.ActiveXObject || !window.postMessage) { + return function(fn){ fn() }; + } + + // based on setZeroTimeout by David Baron + // - http://dbaron.org/log/20100309-faster-timeouts + var timeouts = [] + , name = 'mocha-zero-timeout' + + window.addEventListener('message', function(e){ + if (e.source == window && e.data == name) { + if (e.stopPropagation) e.stopPropagation(); + if (timeouts.length) timeouts.shift()(); + } + }, true); + + return function(fn){ + timeouts.push(fn); + window.postMessage(name, '*'); + } +})(); + +/** + * Remove uncaughtException listener. + */ + +process.removeListener = function(e){ + if ('uncaughtException' == e) { + window.onerror = null; + } +}; + +/** + * Implements uncaughtException listener. + */ + +process.on = function(e, fn){ + if ('uncaughtException' == e) { + window.onerror = fn; + } +}; + +/** + * Expose mocha. + */ + +window.mocha = require('mocha'); + +// boot +;(function(){ + var suite = new mocha.Suite('', new mocha.Context) + , utils = mocha.utils + , options = {} + + /** + * Highlight the given string of `js`. + */ + + function highlight(js) { + return js + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>') + .replace(/('.*?')/gm, '<span class="string">$1</span>') + .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>') + .replace(/(\d+)/gm, '<span class="number">$1</span>') + .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>') + .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>') + } + + /** + * Highlight code contents. + */ + + function highlightCode() { + var code = document.getElementsByTagName('code'); + for (var i = 0, len = code.length; i < len; ++i) { + code[i].innerHTML = highlight(code[i].innerHTML); + } + } + + /** + * Parse the given `qs`. + */ + + function parse(qs) { + return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){ + var i = pair.indexOf('=') + , key = pair.slice(0, i) + , val = pair.slice(++i); + + obj[key] = decodeURIComponent(val); + return obj; + }, {}); + } + + /** + * Setup mocha with the given setting options. + */ + + mocha.setup = function(opts){ + if ('string' === typeof opts) options.ui = opts; + else options = opts; + + ui = mocha.interfaces[options.ui]; + if (!ui) throw new Error('invalid mocha interface "' + ui + '"'); + if (options.timeout) suite.timeout(options.timeout); + ui(suite); + suite.emit('pre-require', window); + }; + + /** + * Run mocha, returning the Runner. + */ + + mocha.run = function(fn){ + suite.emit('run'); + var runner = new mocha.Runner(suite); + var Reporter = options.reporter || mocha.reporters.HTML; + var reporter = new Reporter(runner); + var query = parse(window.location.search || ""); + if (query.grep) runner.grep(new RegExp(query.grep)); + if (options.ignoreLeaks) runner.ignoreLeaks = true; + if (options.globals) runner.globals(options.globals); + runner.globals(['location']); + runner.on('end', highlightCode); + return runner.run(fn); + }; +})(); +})();
\ No newline at end of file diff --git a/node_modules/request/node_modules/qs/test/browser/qs.css b/node_modules/request/node_modules/qs/test/browser/qs.css new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/node_modules/request/node_modules/qs/test/browser/qs.css diff --git a/node_modules/request/node_modules/qs/test/browser/qs.js b/node_modules/request/node_modules/qs/test/browser/qs.js new file mode 100644 index 000000000..452d197a9 --- /dev/null +++ b/node_modules/request/node_modules/qs/test/browser/qs.js @@ -0,0 +1,351 @@ + +/** + * Require the given path. + * + * @param {String} path + * @return {Object} exports + * @api public + */ + +function require(p, parent){ + var path = require.resolve(p) + , mod = require.modules[path]; + if (!mod) throw new Error('failed to require "' + p + '" in ' + parent); + if (!mod.exports) { + mod.exports = {}; + mod.client = true; + mod.call(mod.exports, mod, mod.exports, require.relative(path)); + } + return mod.exports; +} + +/** + * Registered modules. + */ + +require.modules = {}; + +/** + * Resolve `path`. + * + * @param {String} path + * @return {Object} module + * @api public + */ + +require.resolve = function(path){ + var orig = path + , reg = path + '.js' + , index = path + '/index.js'; + return require.modules[reg] && reg + || require.modules[index] && index + || orig; +}; + +/** + * Register module at `path` with callback `fn`. + * + * @param {String} path + * @param {Function} fn + * @api public + */ + +require.register = function(path, fn){ + require.modules[path] = fn; +}; + +/** + * Defines and executes anonymous module immediately, while preserving relative + * paths. + * + * @param {String} path + * @param {Function} require ref + * @api public + */ + +require.exec = function (path, fn) { + fn.call(window, require.relative(path)); +}; + +/** + * Return a require function relative to the `parent` path. + * + * @param {String} parent + * @return {Function} + * @api private + */ + +require.relative = function(parent) { + return function(p){ + if ('.' != p[0]) return require(p); + + var path = parent.split('/') + , segs = p.split('/'); + path.pop(); + + for (var i = 0; i < segs.length; i++) { + var seg = segs[i]; + if ('..' == seg) path.pop(); + else if ('.' != seg) path.push(seg); + } + + return require(path.join('/'), parent); + }; +}; +// component qs: querystring +require.register("querystring", function(module, exports, require){ +;(function(){ + +/** + * Object#toString() ref for stringify(). + */ + +var toString = Object.prototype.toString; + +/** + * Cache non-integer test regexp. + */ + +var isint = /^[0-9]+$/; + +function promote(parent, key) { + if (parent[key].length == 0) return parent[key] = {}; + var t = {}; + for (var i in parent[key]) t[i] = parent[key][i]; + parent[key] = t; + return t; +} + +function parse(parts, parent, key, val) { + var part = parts.shift(); + // end + if (!part) { + if (Array.isArray(parent[key])) { + parent[key].push(val); + } else if ('object' == typeof parent[key]) { + parent[key] = val; + } else if ('undefined' == typeof parent[key]) { + parent[key] = val; + } else { + parent[key] = [parent[key], val]; + } + // array + } else { + var obj = parent[key] = parent[key] || []; + if (']' == part) { + if (Array.isArray(obj)) { + if ('' != val) obj.push(val); + } else if ('object' == typeof obj) { + obj[Object.keys(obj).length] = val; + } else { + obj = parent[key] = [parent[key], val]; + } + // prop + } else if (~part.indexOf(']')) { + part = part.substr(0, part.length - 1); + if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + // key + } else { + if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + } + } +} + +/** + * Merge parent key/val pair. + */ + +function merge(parent, key, val){ + if (~key.indexOf(']')) { + var parts = key.split('[') + , len = parts.length + , last = len - 1; + parse(parts, parent, 'base', val); + // optimize + } else { + if (!isint.test(key) && Array.isArray(parent.base)) { + var t = {}; + for (var k in parent.base) t[k] = parent.base[k]; + parent.base = t; + } + set(parent.base, key, val); + } + + return parent; +} + +/** + * Parse the given obj. + */ + +function parseObject(obj){ + var ret = { base: {} }; + Object.keys(obj).forEach(function(name){ + merge(ret, name, obj[name]); + }); + return ret.base; +} + +/** + * Parse the given str. + */ + +function parseString(str){ + return String(str) + .split('&') + .reduce(function(ret, pair){ + try{ + pair = decodeURIComponent(pair.replace(/\+/g, ' ')); + } catch(e) { + // ignore + } + + var eql = pair.indexOf('=') + , brace = lastBraceInKey(pair) + , key = pair.substr(0, brace || eql) + , val = pair.substr(brace || eql, pair.length) + , val = val.substr(val.indexOf('=') + 1, val.length); + + // ?foo + if ('' == key) key = pair, val = ''; + + return merge(ret, key, val); + }, { base: {} }).base; +} + +/** + * Parse the given query `str` or `obj`, returning an object. + * + * @param {String} str | {Object} obj + * @return {Object} + * @api public + */ + +exports.parse = function(str){ + if (null == str || '' == str) return {}; + return 'object' == typeof str + ? parseObject(str) + : parseString(str); +}; + +/** + * Turn the given `obj` into a query string + * + * @param {Object} obj + * @return {String} + * @api public + */ + +var stringify = exports.stringify = function(obj, prefix) { + if (Array.isArray(obj)) { + return stringifyArray(obj, prefix); + } else if ('[object Object]' == toString.call(obj)) { + return stringifyObject(obj, prefix); + } else if ('string' == typeof obj) { + return stringifyString(obj, prefix); + } else { + return prefix + '=' + obj; + } +}; + +/** + * Stringify the given `str`. + * + * @param {String} str + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyString(str, prefix) { + if (!prefix) throw new TypeError('stringify expects an object'); + return prefix + '=' + encodeURIComponent(str); +} + +/** + * Stringify the given `arr`. + * + * @param {Array} arr + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyArray(arr, prefix) { + var ret = []; + if (!prefix) throw new TypeError('stringify expects an object'); + for (var i = 0; i < arr.length; i++) { + ret.push(stringify(arr[i], prefix + '['+i+']')); + } + return ret.join('&'); +} + +/** + * Stringify the given `obj`. + * + * @param {Object} obj + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyObject(obj, prefix) { + var ret = [] + , keys = Object.keys(obj) + , key; + + for (var i = 0, len = keys.length; i < len; ++i) { + key = keys[i]; + ret.push(stringify(obj[key], prefix + ? prefix + '[' + encodeURIComponent(key) + ']' + : encodeURIComponent(key))); + } + + return ret.join('&'); +} + +/** + * Set `obj`'s `key` to `val` respecting + * the weird and wonderful syntax of a qs, + * where "foo=bar&foo=baz" becomes an array. + * + * @param {Object} obj + * @param {String} key + * @param {String} val + * @api private + */ + +function set(obj, key, val) { + var v = obj[key]; + if (undefined === v) { + obj[key] = val; + } else if (Array.isArray(v)) { + v.push(val); + } else { + obj[key] = [v, val]; + } +} + +/** + * Locate last brace in `str` within the key. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function lastBraceInKey(str) { + var len = str.length + , brace + , c; + for (var i = 0; i < len; ++i) { + c = str[i]; + if (']' == c) brace = false; + if ('[' == c) brace = true; + if ('=' == c && !brace) return i; + } +} +})(); +}); diff --git a/node_modules/request/node_modules/qs/test/parse.js b/node_modules/request/node_modules/qs/test/parse.js new file mode 100644 index 000000000..be827a8a0 --- /dev/null +++ b/node_modules/request/node_modules/qs/test/parse.js @@ -0,0 +1,147 @@ + +if (require.register) { + var qs = require('querystring'); +} else { + var qs = require('../') + , expect = require('expect.js'); +} + +describe('qs.parse()', function(){ + it('should support the basics', function(){ + expect(qs.parse('0=foo')).to.eql({ '0': 'foo' }); + + expect(qs.parse('foo=c++')) + .to.eql({ foo: 'c ' }); + + expect(qs.parse('a[>=]=23')) + .to.eql({ a: { '>=': '23' }}); + + expect(qs.parse('a[<=>]==23')) + .to.eql({ a: { '<=>': '=23' }}); + + expect(qs.parse('a[==]=23')) + .to.eql({ a: { '==': '23' }}); + + expect(qs.parse('foo')) + .to.eql({ foo: '' }); + + expect(qs.parse('foo=bar')) + .to.eql({ foo: 'bar' }); + + expect(qs.parse(' foo = bar = baz ')) + .to.eql({ ' foo ': ' bar = baz ' }); + + expect(qs.parse('foo=bar=baz')) + .to.eql({ foo: 'bar=baz' }); + + expect(qs.parse('foo=bar&bar=baz')) + .to.eql({ foo: 'bar', bar: 'baz' }); + + expect(qs.parse('foo=bar&baz')) + .to.eql({ foo: 'bar', baz: '' }); + + expect(qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World')) + .to.eql({ + cht: 'p3' + , chd: 't:60,40' + , chs: '250x100' + , chl: 'Hello|World' + }); + }) + + it('should support encoded = signs', function(){ + expect(qs.parse('he%3Dllo=th%3Dere')) + .to.eql({ 'he=llo': 'th=ere' }); + }) + + it('should support nesting', function(){ + expect(qs.parse('ops[>=]=25')) + .to.eql({ ops: { '>=': '25' }}); + + expect(qs.parse('user[name]=tj')) + .to.eql({ user: { name: 'tj' }}); + + expect(qs.parse('user[name][first]=tj&user[name][last]=holowaychuk')) + .to.eql({ user: { name: { first: 'tj', last: 'holowaychuk' }}}); + }) + + it('should support array notation', function(){ + expect(qs.parse('images[]')) + .to.eql({ images: [] }); + + expect(qs.parse('user[]=tj')) + .to.eql({ user: ['tj'] }); + + expect(qs.parse('user[]=tj&user[]=tobi&user[]=jane')) + .to.eql({ user: ['tj', 'tobi', 'jane'] }); + + expect(qs.parse('user[names][]=tj&user[names][]=tyler')) + .to.eql({ user: { names: ['tj', 'tyler'] }}); + + expect(qs.parse('user[names][]=tj&user[names][]=tyler&user[email]=tj@vision-media.ca')) + .to.eql({ user: { names: ['tj', 'tyler'], email: 'tj@vision-media.ca' }}); + + expect(qs.parse('items=a&items=b')) + .to.eql({ items: ['a', 'b'] }); + + expect(qs.parse('user[names]=tj&user[names]=holowaychuk&user[names]=TJ')) + .to.eql({ user: { names: ['tj', 'holowaychuk', 'TJ'] }}); + + expect(qs.parse('user[name][first]=tj&user[name][first]=TJ')) + .to.eql({ user: { name: { first: ['tj', 'TJ'] }}}); + + var o = qs.parse('existing[fcbaebfecc][name][last]=tj') + expect(o).to.eql({ existing: { 'fcbaebfecc': { name: { last: 'tj' }}}}) + expect(Array.isArray(o.existing)).to.equal(false); + }) + + it('should support arrays with indexes', function(){ + expect(qs.parse('foo[0]=bar&foo[1]=baz')).to.eql({ foo: ['bar', 'baz'] }); + expect(qs.parse('foo[1]=bar&foo[0]=baz')).to.eql({ foo: ['baz', 'bar'] }); + expect(qs.parse('foo[base64]=RAWR')).to.eql({ foo: { base64: 'RAWR' }}); + expect(qs.parse('foo[64base]=RAWR')).to.eql({ foo: { '64base': 'RAWR' }}); + }) + + it('should expand to an array when dupliate keys are present', function(){ + expect(qs.parse('items=bar&items=baz&items=raz')) + .to.eql({ items: ['bar', 'baz', 'raz'] }); + }) + + it('should support right-hand side brackets', function(){ + expect(qs.parse('pets=["tobi"]')) + .to.eql({ pets: '["tobi"]' }); + + expect(qs.parse('operators=[">=", "<="]')) + .to.eql({ operators: '[">=", "<="]' }); + + expect(qs.parse('op[>=]=[1,2,3]')) + .to.eql({ op: { '>=': '[1,2,3]' }}); + + expect(qs.parse('op[>=]=[1,2,3]&op[=]=[[[[1]]]]')) + .to.eql({ op: { '>=': '[1,2,3]', '=': '[[[[1]]]]' }}); + }) + + it('should support empty values', function(){ + expect(qs.parse('')).to.eql({}); + expect(qs.parse(undefined)).to.eql({}); + expect(qs.parse(null)).to.eql({}); + }) + + it('should transform arrays to objects', function(){ + expect(qs.parse('foo[0]=bar&foo[bad]=baz')).to.eql({ foo: { 0: "bar", bad: "baz" }}); + expect(qs.parse('foo[bad]=baz&foo[0]=bar')).to.eql({ foo: { 0: "bar", bad: "baz" }}); + }) + + it('should support malformed uri chars', function(){ + expect(qs.parse('{%:%}')).to.eql({ '{%:%}': '' }); + expect(qs.parse('foo=%:%}')).to.eql({ 'foo': '%:%}' }); + }) + + it('should support semi-parsed strings', function(){ + expect(qs.parse({ 'user[name]': 'tobi' })) + .to.eql({ user: { name: 'tobi' }}); + + expect(qs.parse({ 'user[name]': 'tobi', 'user[email][main]': 'tobi@lb.com' })) + .to.eql({ user: { name: 'tobi', email: { main: 'tobi@lb.com' } }}); + }) +})
\ No newline at end of file diff --git a/node_modules/request/node_modules/qs/test/stringify.js b/node_modules/request/node_modules/qs/test/stringify.js new file mode 100644 index 000000000..3dc694eda --- /dev/null +++ b/node_modules/request/node_modules/qs/test/stringify.js @@ -0,0 +1,80 @@ + +if (require.register) { + var qs = require('querystring'); +} else { + var qs = require('../') + , expect = require('expect.js'); +} + +var date = new Date(0); + +var str_identities = { + 'basics': [ + { str: 'foo=bar', obj: {'foo' : 'bar'}}, + { str: 'foo=%22bar%22', obj: {'foo' : '\"bar\"'}}, + { str: 'foo=', obj: {'foo': ''}}, + { str: 'foo=1&bar=2', obj: {'foo' : '1', 'bar' : '2'}}, + { str: 'my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F', obj: {'my weird field': "q1!2\"'w$5&7/z8)?"}}, + { str: 'foo%3Dbaz=bar', obj: {'foo=baz': 'bar'}}, + { str: 'foo=bar&bar=baz', obj: {foo: 'bar', bar: 'baz'}}, + { str: 'foo=bar&baz=&raz=', obj: { foo: 'bar', baz: null, raz: undefined }} + ], + 'escaping': [ + { str: 'foo=foo%20bar', obj: {foo: 'foo bar'}}, + { str: 'cht=p3&chd=t%3A60%2C40&chs=250x100&chl=Hello%7CWorld', obj: { + cht: 'p3' + , chd: 't:60,40' + , chs: '250x100' + , chl: 'Hello|World' + }} + ], + 'nested': [ + { str: 'foo[0]=bar&foo[1]=quux', obj: {'foo' : ['bar', 'quux']}}, + { str: 'foo[0]=bar', obj: {foo: ['bar']}}, + { str: 'foo[0]=1&foo[1]=2', obj: {'foo' : ['1', '2']}}, + { str: 'foo=bar&baz[0]=1&baz[1]=2&baz[2]=3', obj: {'foo' : 'bar', 'baz' : ['1', '2', '3']}}, + { str: 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3', obj: {'foo' : ['bar'], 'baz' : ['1', '2', '3']}}, + { str: 'x[y][z]=1', obj: {'x' : {'y' : {'z' : '1'}}}}, + { str: 'x[y][z][0]=1', obj: {'x' : {'y' : {'z' : ['1']}}}}, + { str: 'x[y][z]=2', obj: {'x' : {'y' : {'z' : '2'}}}}, + { str: 'x[y][z][0]=1&x[y][z][1]=2', obj: {'x' : {'y' : {'z' : ['1', '2']}}}}, + { str: 'x[y][0][z]=1', obj: {'x' : {'y' : [{'z' : '1'}]}}}, + { str: 'x[y][0][z][0]=1', obj: {'x' : {'y' : [{'z' : ['1']}]}}}, + { str: 'x[y][0][z]=1&x[y][0][w]=2', obj: {'x' : {'y' : [{'z' : '1', 'w' : '2'}]}}}, + { str: 'x[y][0][v][w]=1', obj: {'x' : {'y' : [{'v' : {'w' : '1'}}]}}}, + { str: 'x[y][0][z]=1&x[y][0][v][w]=2', obj: {'x' : {'y' : [{'z' : '1', 'v' : {'w' : '2'}}]}}}, + { str: 'x[y][0][z]=1&x[y][1][z]=2', obj: {'x' : {'y' : [{'z' : '1'}, {'z' : '2'}]}}}, + { str: 'x[y][0][z]=1&x[y][0][w]=a&x[y][1][z]=2&x[y][1][w]=3', obj: {'x' : {'y' : [{'z' : '1', 'w' : 'a'}, {'z' : '2', 'w' : '3'}]}}}, + { str: 'user[name][first]=tj&user[name][last]=holowaychuk', obj: { user: { name: { first: 'tj', last: 'holowaychuk' }}}} + ], + 'errors': [ + { obj: 'foo=bar', message: 'stringify expects an object' }, + { obj: ['foo', 'bar'], message: 'stringify expects an object' } + ], + 'numbers': [ + { str: 'limit[0]=1&limit[1]=2&limit[2]=3', obj: { limit: [1, 2, '3'] }}, + { str: 'limit=1', obj: { limit: 1 }} + ], + 'others': [ + { str: 'at=' + encodeURIComponent(date), obj: { at: date } } + ] +}; + +function test(type) { + return function(){ + var str, obj; + for (var i = 0; i < str_identities[type].length; i++) { + str = str_identities[type][i].str; + obj = str_identities[type][i].obj; + expect(qs.stringify(obj)).to.eql(str); + } + } +} + +describe('qs.stringify()', function(){ + it('should support the basics', test('basics')) + it('should support escapes', test('escaping')) + it('should support nesting', test('nested')) + it('should support numbers', test('numbers')) + it('should support others', test('others')) +}) diff --git a/node_modules/request/node_modules/tunnel-agent/index.js b/node_modules/request/node_modules/tunnel-agent/index.js new file mode 100644 index 000000000..3f7bbb909 --- /dev/null +++ b/node_modules/request/node_modules/tunnel-agent/index.js @@ -0,0 +1,227 @@ +'use strict' + +var net = require('net') + , tls = require('tls') + , http = require('http') + , https = require('https') + , events = require('events') + , assert = require('assert') + , util = require('util') + ; + +exports.httpOverHttp = httpOverHttp +exports.httpsOverHttp = httpsOverHttp +exports.httpOverHttps = httpOverHttps +exports.httpsOverHttps = httpsOverHttps + + +function httpOverHttp(options) { + var agent = new TunnelingAgent(options) + agent.request = http.request + return agent +} + +function httpsOverHttp(options) { + var agent = new TunnelingAgent(options) + agent.request = http.request + agent.createSocket = createSecureSocket + return agent +} + +function httpOverHttps(options) { + var agent = new TunnelingAgent(options) + agent.request = https.request + return agent +} + +function httpsOverHttps(options) { + var agent = new TunnelingAgent(options) + agent.request = https.request + agent.createSocket = createSecureSocket + return agent +} + + +function TunnelingAgent(options) { + var self = this + self.options = options || {} + self.proxyOptions = self.options.proxy || {} + self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets + self.requests = [] + self.sockets = [] + + self.on('free', function onFree(socket, host, port) { + for (var i = 0, len = self.requests.length; i < len; ++i) { + var pending = self.requests[i] + if (pending.host === host && pending.port === port) { + // Detect the request to connect same origin server, + // reuse the connection. + self.requests.splice(i, 1) + pending.request.onSocket(socket) + return + } + } + socket.destroy() + self.removeSocket(socket) + }) +} +util.inherits(TunnelingAgent, events.EventEmitter) + +TunnelingAgent.prototype.addRequest = function addRequest(req, host, port) { + var self = this + + if (self.sockets.length >= this.maxSockets) { + // We are over limit so we'll add it to the queue. + self.requests.push({host: host, port: port, request: req}) + return + } + + // If we are under maxSockets create a new one. + self.createSocket({host: host, port: port, request: req}, function(socket) { + socket.on('free', onFree) + socket.on('close', onCloseOrRemove) + socket.on('agentRemove', onCloseOrRemove) + req.onSocket(socket) + + function onFree() { + self.emit('free', socket, host, port) + } + + function onCloseOrRemove(err) { + self.removeSocket() + socket.removeListener('free', onFree) + socket.removeListener('close', onCloseOrRemove) + socket.removeListener('agentRemove', onCloseOrRemove) + } + }) +} + +TunnelingAgent.prototype.createSocket = function createSocket(options, cb) { + var self = this + var placeholder = {} + self.sockets.push(placeholder) + + var connectOptions = mergeOptions({}, self.proxyOptions, + { method: 'CONNECT' + , path: options.host + ':' + options.port + , agent: false + } + ) + if (connectOptions.proxyAuth) { + connectOptions.headers = connectOptions.headers || {} + connectOptions.headers['Proxy-Authorization'] = 'Basic ' + + new Buffer(connectOptions.proxyAuth).toString('base64') + } + + debug('making CONNECT request') + var connectReq = self.request(connectOptions) + connectReq.useChunkedEncodingByDefault = false // for v0.6 + connectReq.once('response', onResponse) // for v0.6 + connectReq.once('upgrade', onUpgrade) // for v0.6 + connectReq.once('connect', onConnect) // for v0.7 or later + connectReq.once('error', onError) + connectReq.end() + + function onResponse(res) { + // Very hacky. This is necessary to avoid http-parser leaks. + res.upgrade = true + } + + function onUpgrade(res, socket, head) { + // Hacky. + process.nextTick(function() { + onConnect(res, socket, head) + }) + } + + function onConnect(res, socket, head) { + connectReq.removeAllListeners() + socket.removeAllListeners() + + if (res.statusCode === 200) { + assert.equal(head.length, 0) + debug('tunneling connection has established') + self.sockets[self.sockets.indexOf(placeholder)] = socket + cb(socket) + } else { + debug('tunneling socket could not be established, statusCode=%d', res.statusCode) + var error = new Error('tunneling socket could not be established, ' + 'statusCode=' + res.statusCode) + error.code = 'ECONNRESET' + options.request.emit('error', error) + self.removeSocket(placeholder) + } + } + + function onError(cause) { + connectReq.removeAllListeners() + + debug('tunneling socket could not be established, cause=%s\n', cause.message, cause.stack) + var error = new Error('tunneling socket could not be established, ' + 'cause=' + cause.message) + error.code = 'ECONNRESET' + options.request.emit('error', error) + self.removeSocket(placeholder) + } +} + +TunnelingAgent.prototype.removeSocket = function removeSocket(socket) { + var pos = this.sockets.indexOf(socket) + if (pos === -1) return + + this.sockets.splice(pos, 1) + + var pending = this.requests.shift() + if (pending) { + // If we have pending requests and a socket gets closed a new one + // needs to be created to take over in the pool for the one that closed. + this.createSocket(pending, function(socket) { + pending.request.onSocket(socket) + }) + } +} + +function createSecureSocket(options, cb) { + var self = this + TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { + // 0 is dummy port for v0.6 + var secureSocket = tls.connect(0, mergeOptions({}, self.options, + { servername: options.host + , socket: socket + } + )) + cb(secureSocket) + }) +} + + +function mergeOptions(target) { + for (var i = 1, len = arguments.length; i < len; ++i) { + var overrides = arguments[i] + if (typeof overrides === 'object') { + var keys = Object.keys(overrides) + for (var j = 0, keyLen = keys.length; j < keyLen; ++j) { + var k = keys[j] + if (overrides[k] !== undefined) { + target[k] = overrides[k] + } + } + } + } + return target +} + + +var debug +if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { + debug = function() { + var args = Array.prototype.slice.call(arguments) + if (typeof args[0] === 'string') { + args[0] = 'TUNNEL: ' + args[0] + } else { + args.unshift('TUNNEL:') + } + console.error.apply(console, args) + } +} else { + debug = function() {} +} +exports.debug = debug // for test diff --git a/node_modules/request/node_modules/tunnel-agent/package.json b/node_modules/request/node_modules/tunnel-agent/package.json new file mode 100644 index 000000000..24745fb63 --- /dev/null +++ b/node_modules/request/node_modules/tunnel-agent/package.json @@ -0,0 +1,27 @@ +{ + "author": { + "name": "Mikeal Rogers", + "email": "mikeal.rogers@gmail.com", + "url": "http://www.futurealoof.com" + }, + "name": "tunnel-agent", + "description": "HTTP proxy tunneling agent. Formerly part of mikeal/request, now a standalone module.", + "version": "0.2.0", + "repository": { + "url": "https://github.com/mikeal/tunnel-agent" + }, + "main": "index.js", + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "_id": "tunnel-agent@0.2.0", + "readme": "ERROR: No README.md file found!", + "dist": { + "shasum": "4927e7d29250f1d064e82922a5e608409cdb3cf4" + }, + "_from": "tunnel-agent@~0.2.0", + "_resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.2.0.tgz" +} diff --git a/node_modules/request/oauth.js b/node_modules/request/oauth.js deleted file mode 100644 index ebde3fd26..000000000 --- a/node_modules/request/oauth.js +++ /dev/null @@ -1,34 +0,0 @@ -var crypto = require('crypto') - , qs = require('querystring') - ; - -function sha1 (key, body) { - return crypto.createHmac('sha1', key).update(body).digest('base64') -} - -function rfc3986 (str) { - return encodeURIComponent(str) - .replace(/!/g,'%21') - .replace(/\*/g,'%2A') - .replace(/\(/g,'%28') - .replace(/\)/g,'%29') - .replace(/'/g,'%27') - ; -} - -function hmacsign (httpMethod, base_uri, params, consumer_secret, token_secret, body) { - // adapted from https://dev.twitter.com/docs/auth/oauth - var base = - (httpMethod || 'GET') + "&" + - encodeURIComponent( base_uri ) + "&" + - Object.keys(params).sort().map(function (i) { - // big WTF here with the escape + encoding but it's what twitter wants - return escape(rfc3986(i)) + "%3D" + escape(rfc3986(params[i])) - }).join("%26") - var key = encodeURIComponent(consumer_secret) + '&' - if (token_secret) key += encodeURIComponent(token_secret) - return sha1(key, base) -} - -exports.hmacsign = hmacsign -exports.rfc3986 = rfc3986
\ No newline at end of file diff --git a/node_modules/request/package.json b/node_modules/request/package.json index 05d314449..bc02c5a1d 100644..100755 --- a/node_modules/request/package.json +++ b/node_modules/request/package.json @@ -7,7 +7,7 @@ "util", "utility" ], - "version": "2.9.203", + "version": "2.16.6", "author": { "name": "Mikeal Rogers", "email": "mikeal.rogers@gmail.com" @@ -20,16 +20,27 @@ "url": "http://github.com/mikeal/request/issues" }, "engines": [ - "node >= 0.3.6" + "node >= 0.8.0" ], - "main": "./main", + "main": "index.js", + "dependencies": { + "form-data": "~0.0.3", + "mime": "~1.2.7", + "hawk": "~0.10.2", + "node-uuid": "~1.4.0", + "cookie-jar": "~0.2.0", + "aws-sign": "~0.2.0", + "oauth-sign": "~0.2.0", + "forever-agent": "~0.2.0", + "tunnel-agent": "~0.2.0", + "json-stringify-safe": "~3.0.0", + "qs": "~0.5.4" + }, "scripts": { "test": "node tests/run.js" }, - "readme": "# Request -- Simplified HTTP request method\n\n## Install\n\n<pre>\n npm install request\n</pre>\n\nOr from source:\n\n<pre>\n git clone git://github.com/mikeal/request.git \n cd request\n npm link\n</pre>\n\n## Super simple to use\n\nRequest is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default.\n\n```javascript\nvar request = require('request');\nrequest('http://www.google.com', function (error, response, body) {\n if (!error && response.statusCode == 200) {\n console.log(body) // Print the google web page.\n }\n})\n```\n\n## Streaming\n\nYou can stream any response to a file stream.\n\n```javascript\nrequest('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))\n```\n\nYou can also stream a file to a PUT or POST request. This method will also check the file extension against a mapping of file extensions to content-types, in this case `application/json`, and use the proper content-type in the PUT request if one is not already provided in the headers.\n\n```javascript\nfs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))\n```\n\nRequest can also pipe to itself. When doing so the content-type and content-length will be preserved in the PUT headers.\n\n```javascript\nrequest.get('http://google.com/img.png').pipe(request.put('http://mysite.com/img.png'))\n```\n\nNow let's get fancy.\n\n```javascript\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n if (req.method === 'PUT') {\n req.pipe(request.put('http://mysite.com/doodle.png'))\n } else if (req.method === 'GET' || req.method === 'HEAD') {\n request.get('http://mysite.com/doodle.png').pipe(resp)\n } \n }\n})\n```\n\nYou can also pipe() from a http.ServerRequest instance and to a http.ServerResponse instance. The HTTP method and headers will be sent as well as the entity-body data. Which means that, if you don't really care about security, you can do:\n\n```javascript\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n var x = request('http://mysite.com/doodle.png')\n req.pipe(x)\n x.pipe(resp)\n }\n})\n```\n\nAnd since pipe() returns the destination stream in node 0.5.x you can do one line proxying :)\n\n```javascript\nreq.pipe(request('http://mysite.com/doodle.png')).pipe(resp)\n```\n\nAlso, none of this new functionality conflicts with requests previous features, it just expands them.\n\n```javascript\nvar r = request.defaults({'proxy':'http://localproxy.com'})\n\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n r.get('http://google.com/doodle.png').pipe(resp)\n }\n})\n```\n\nYou can still use intermediate proxies, the requests will still follow HTTP forwards, etc.\n\n## OAuth Signing\n\n```javascript\n// Twitter OAuth\nvar qs = require('querystring')\n , oauth =\n { callback: 'http://mysite.com/callback/'\n , consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n }\n , url = 'https://api.twitter.com/oauth/request_token'\n ;\nrequest.post({url:url, oauth:oauth}, function (e, r, body) {\n // Assume by some stretch of magic you aquired the verifier\n var access_token = qs.parse(body)\n , oauth = \n { consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n , token: access_token.oauth_token\n , verifier: VERIFIER\n , token_secret: access_token.oauth_token_secret\n }\n , url = 'https://api.twitter.com/oauth/access_token'\n ;\n request.post({url:url, oauth:oauth}, function (e, r, body) {\n var perm_token = qs.parse(body)\n , oauth = \n { consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n , token: perm_token.oauth_token\n , token_secret: perm_token.oauth_token_secret\n }\n , url = 'https://api.twitter.com/1/users/show.json?'\n , params = \n { screen_name: perm_token.screen_name\n , user_id: perm_token.user_id\n }\n ;\n url += qs.stringify(params)\n request.get({url:url, oauth:oauth, json:true}, function (e, r, user) {\n console.log(user)\n })\n })\n})\n```\n\n\n\n### request(options, callback)\n\nThe first argument can be either a url or an options object. The only required option is uri, all others are optional.\n\n* `uri` || `url` - fully qualified uri or a parsed url object from url.parse()\n* `qs` - object containing querystring values to be appended to the uri\n* `method` - http method, defaults to GET\n* `headers` - http headers, defaults to {}\n* `body` - entity body for POST and PUT requests. Must be buffer or string.\n* `form` - sets `body` but to querystring representation of value and adds `Content-type: application/x-www-form-urlencoded; charset=utf-8` header.\n* `json` - sets `body` but to JSON representation of value and adds `Content-type: application/json` header. Additionally, parses the response body as json.\n* `multipart` - (experimental) array of objects which contains their own headers and `body` attribute. Sends `multipart/related` request. See example below.\n* `followRedirect` - follow HTTP 3xx responses as redirects. defaults to true.\n* `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects. defaults to false.\n* `maxRedirects` - the maximum number of redirects to follow, defaults to 10.\n* `encoding` - Encoding to be used on `setEncoding` of response data. If set to `null`, the body is returned as a Buffer.\n* `pool` - A hash object containing the agents for these requests. If omitted this request will use the global pool which is set to node's default maxSockets.\n* `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool.\n* `timeout` - Integer containing the number of milliseconds to wait for a request to respond before aborting the request\t\n* `proxy` - An HTTP proxy to be used. Support proxy Auth with Basic Auth the same way it's supported with the `url` parameter by embedding the auth info in the uri.\n* `oauth` - Options for OAuth HMAC-SHA1 signing, see documentation above.\n* `strictSSL` - Set to `true` to require that SSL certificates be valid. Note: to use your own certificate authority, you need to specify an agent that was created with that ca as an option.\n* `jar` - Set to `false` if you don't want cookies to be remembered for future use or define your custom cookie jar (see examples section)\n\n\nThe callback argument gets 3 arguments. The first is an error when applicable (usually from the http.Client option not the http.ClientRequest object). The second in an http.ClientResponse object. The third is the response body String or Buffer.\n\n## Convenience methods\n\nThere are also shorthand methods for different HTTP METHODs and some other conveniences.\n\n### request.defaults(options) \n \nThis method returns a wrapper around the normal request API that defaults to whatever options you pass in to it.\n\n### request.put\n\nSame as request() but defaults to `method: \"PUT\"`.\n\n```javascript\nrequest.put(url)\n```\n\n### request.post\n\nSame as request() but defaults to `method: \"POST\"`.\n\n```javascript\nrequest.post(url)\n```\n\n### request.head\n\nSame as request() but defaults to `method: \"HEAD\"`.\n\n```javascript\nrequest.head(url)\n```\n\n### request.del\n\nSame as request() but defaults to `method: \"DELETE\"`.\n\n```javascript\nrequest.del(url)\n```\n\n### request.get\n\nAlias to normal request method for uniformity.\n\n```javascript\nrequest.get(url)\n```\n### request.cookie\n\nFunction that creates a new cookie.\n\n```javascript\nrequest.cookie('cookie_string_here')\n```\n### request.jar\n\nFunction that creates a new cookie jar.\n\n```javascript\nrequest.jar()\n```\n\n\n## Examples:\n\n```javascript\n var request = require('request')\n , rand = Math.floor(Math.random()*100000000).toString()\n ;\n request(\n { method: 'PUT'\n , uri: 'http://mikeal.iriscouch.com/testjs/' + rand\n , multipart: \n [ { 'content-type': 'application/json'\n , body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})\n }\n , { body: 'I am an attachment' }\n ] \n }\n , function (error, response, body) {\n if(response.statusCode == 201){\n console.log('document saved as: http://mikeal.iriscouch.com/testjs/'+ rand)\n } else {\n console.log('error: '+ response.statusCode)\n console.log(body)\n }\n }\n )\n```\nCookies are enabled by default (so they can be used in subsequent requests). To disable cookies set jar to false (either in defaults or in the options sent).\n\n```javascript\nvar request = request.defaults({jar: false})\nrequest('http://www.google.com', function () {\n request('http://images.google.com')\n})\n```\n\nIf you to use a custom cookie jar (instead of letting request use its own global cookie jar) you do so by setting the jar default or by specifying it as an option:\n\n```javascript\nvar j = request.jar()\nvar request = request.defaults({jar:j})\nrequest('http://www.google.com', function () {\n request('http://images.google.com')\n})\n```\nOR\n\n```javascript\nvar j = request.jar()\nvar cookie = request.cookie('your_cookie_here')\nj.add(cookie)\nrequest({url: 'http://www.google.com', jar: j}, function () {\n request('http://images.google.com')\n})\n```\n", - "_id": "request@2.9.203", - "dist": { - "shasum": "baf55a9b2ccfcca405cfcc0b104edf8b2681eeef" - }, - "_from": "git://github.com/isaacs/request" + "readme": "# Request -- Simplified HTTP request method\n\n## Install\n\n<pre>\n npm install request\n</pre>\n\nOr from source:\n\n<pre>\n git clone git://github.com/mikeal/request.git \n cd request\n npm link\n</pre>\n\n## Super simple to use\n\nRequest is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default.\n\n```javascript\nvar request = require('request');\nrequest('http://www.google.com', function (error, response, body) {\n if (!error && response.statusCode == 200) {\n console.log(body) // Print the google web page.\n }\n})\n```\n\n## Streaming\n\nYou can stream any response to a file stream.\n\n```javascript\nrequest('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))\n```\n\nYou can also stream a file to a PUT or POST request. This method will also check the file extension against a mapping of file extensions to content-types, in this case `application/json`, and use the proper content-type in the PUT request if one is not already provided in the headers.\n\n```javascript\nfs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))\n```\n\nRequest can also pipe to itself. When doing so the content-type and content-length will be preserved in the PUT headers.\n\n```javascript\nrequest.get('http://google.com/img.png').pipe(request.put('http://mysite.com/img.png'))\n```\n\nNow let's get fancy.\n\n```javascript\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n if (req.method === 'PUT') {\n req.pipe(request.put('http://mysite.com/doodle.png'))\n } else if (req.method === 'GET' || req.method === 'HEAD') {\n request.get('http://mysite.com/doodle.png').pipe(resp)\n } \n }\n})\n```\n\nYou can also pipe() from a http.ServerRequest instance and to a http.ServerResponse instance. The HTTP method and headers will be sent as well as the entity-body data. Which means that, if you don't really care about security, you can do:\n\n```javascript\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n var x = request('http://mysite.com/doodle.png')\n req.pipe(x)\n x.pipe(resp)\n }\n})\n```\n\nAnd since pipe() returns the destination stream in node 0.5.x you can do one line proxying :)\n\n```javascript\nreq.pipe(request('http://mysite.com/doodle.png')).pipe(resp)\n```\n\nAlso, none of this new functionality conflicts with requests previous features, it just expands them.\n\n```javascript\nvar r = request.defaults({'proxy':'http://localproxy.com'})\n\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n r.get('http://google.com/doodle.png').pipe(resp)\n }\n})\n```\nYou can still use intermediate proxies, the requests will still follow HTTP forwards, etc.\n\n## Forms\n\n`request` supports `application/x-www-form-urlencoded` and `multipart/form-data` form uploads. For `multipart/related` refer to the `multipart` API.\n\nUrl encoded forms are simple\n\n```javascript\nrequest.post('http://service.com/upload', {form:{key:'value'}})\n// or\nrequest.post('http://service.com/upload').form({key:'value'})\n```\n\nFor `multipart/form-data` we use the [form-data](https://github.com/felixge/node-form-data) library by [@felixge](https://github.com/felixge). You don't need to worry about piping the form object or setting the headers, `request` will handle that for you.\n\n```javascript\nvar r = request.post('http://service.com/upload')\nvar form = r.form()\nform.append('my_field', 'my_value')\nform.append('my_buffer', new Buffer([1, 2, 3]))\nform.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png'))\nform.append('remote_file', request('http://google.com/doodle.png'))\n```\n\n## HTTP Authentication\n\n```javascript\nrequest.auth('username', 'password', false).get('http://some.server.com/');\n// or\nrequest.get('http://some.server.com/', {\n 'auth': {\n 'user': 'username',\n 'pass': 'password',\n 'sendImmediately': false\n }\n});\n```\n\nIf passed as an option, `auth` should be a hash containing values `user` || `username`, `password` || `pass`, and `sendImmediately` (optional). The method form takes parameters `auth(username, password, sendImmediately)`.\n\n`sendImmediately` defaults to true, which will cause a basic authentication header to be sent. If `sendImmediately` is `false`, then `request` will retry with a proper authentication header after receiving a 401 response from the server (which must contain a `WWW-Authenticate` header indicating the required authentication method).\n\nDigest authentication is supported, but it only works with `sendImmediately` set to `false` (otherwise `request` will send basic authentication on the initial request, which will probably cause the request to fail).\n\n## OAuth Signing\n\n```javascript\n// Twitter OAuth\nvar qs = require('querystring')\n , oauth =\n { callback: 'http://mysite.com/callback/'\n , consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n }\n , url = 'https://api.twitter.com/oauth/request_token'\n ;\nrequest.post({url:url, oauth:oauth}, function (e, r, body) {\n // Ideally, you would take the body in the response\n // and construct a URL that a user clicks on (like a sign in button).\n // The verifier is only available in the response after a user has \n // verified with twitter that they are authorizing your app.\n var access_token = qs.parse(body)\n , oauth = \n { consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n , token: access_token.oauth_token\n , verifier: access_token.oauth_verifier\n }\n , url = 'https://api.twitter.com/oauth/access_token'\n ;\n request.post({url:url, oauth:oauth}, function (e, r, body) {\n var perm_token = qs.parse(body)\n , oauth = \n { consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n , token: perm_token.oauth_token\n , token_secret: perm_token.oauth_token_secret\n }\n , url = 'https://api.twitter.com/1/users/show.json?'\n , params = \n { screen_name: perm_token.screen_name\n , user_id: perm_token.user_id\n }\n ;\n url += qs.stringify(params)\n request.get({url:url, oauth:oauth, json:true}, function (e, r, user) {\n console.log(user)\n })\n })\n})\n```\n\n\n\n### request(options, callback)\n\nThe first argument can be either a url or an options object. The only required option is uri, all others are optional.\n\n* `uri` || `url` - fully qualified uri or a parsed url object from url.parse()\n* `qs` - object containing querystring values to be appended to the uri\n* `method` - http method, defaults to GET\n* `headers` - http headers, defaults to {}\n* `body` - entity body for PATCH, POST and PUT requests. Must be buffer or string.\n* `form` - when passed an object this will set `body` but to a querystring representation of value and adds `Content-type: application/x-www-form-urlencoded; charset=utf-8` header. When passed no option a FormData instance is returned that will be piped to request.\n* `auth` - A hash containing values `user` || `username`, `password` || `pass`, and `sendImmediately` (optional). See documentation above.\n* `json` - sets `body` but to JSON representation of value and adds `Content-type: application/json` header. Additionally, parses the response body as json.\n* `multipart` - (experimental) array of objects which contains their own headers and `body` attribute. Sends `multipart/related` request. See example below.\n* `followRedirect` - follow HTTP 3xx responses as redirects. defaults to true.\n* `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects. defaults to false.\n* `maxRedirects` - the maximum number of redirects to follow, defaults to 10.\n* `encoding` - Encoding to be used on `setEncoding` of response data. If set to `null`, the body is returned as a Buffer.\n* `pool` - A hash object containing the agents for these requests. If omitted this request will use the global pool which is set to node's default maxSockets.\n* `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool.\n* `timeout` - Integer containing the number of milliseconds to wait for a request to respond before aborting the request\t\n* `proxy` - An HTTP proxy to be used. Support proxy Auth with Basic Auth the same way it's supported with the `url` parameter by embedding the auth info in the uri.\n* `oauth` - Options for OAuth HMAC-SHA1 signing, see documentation above.\n* `hawk` - Options for [Hawk signing](https://github.com/hueniverse/hawk). The `credentials` key must contain the necessary signing info, [see hawk docs for details](https://github.com/hueniverse/hawk#usage-example).\n* `strictSSL` - Set to `true` to require that SSL certificates be valid. Note: to use your own certificate authority, you need to specify an agent that was created with that ca as an option.\n* `jar` - Set to `false` if you don't want cookies to be remembered for future use or define your custom cookie jar (see examples section)\n* `aws` - object containing aws signing information, should have the properties `key` and `secret` as well as `bucket` unless you're specifying your bucket as part of the path, or you are making a request that doesn't use a bucket (i.e. GET Services)\n\n\nThe callback argument gets 3 arguments. The first is an error when applicable (usually from the http.Client option not the http.ClientRequest object). The second in an http.ClientResponse object. The third is the response body String or Buffer.\n\n## Convenience methods\n\nThere are also shorthand methods for different HTTP METHODs and some other conveniences.\n\n### request.defaults(options) \n \nThis method returns a wrapper around the normal request API that defaults to whatever options you pass in to it.\n\n### request.put\n\nSame as request() but defaults to `method: \"PUT\"`.\n\n```javascript\nrequest.put(url)\n```\n\n### request.patch\n\nSame as request() but defaults to `method: \"PATCH\"`.\n\n```javascript\nrequest.patch(url)\n```\n\n### request.post\n\nSame as request() but defaults to `method: \"POST\"`.\n\n```javascript\nrequest.post(url)\n```\n\n### request.head\n\nSame as request() but defaults to `method: \"HEAD\"`.\n\n```javascript\nrequest.head(url)\n```\n\n### request.del\n\nSame as request() but defaults to `method: \"DELETE\"`.\n\n```javascript\nrequest.del(url)\n```\n\n### request.get\n\nAlias to normal request method for uniformity.\n\n```javascript\nrequest.get(url)\n```\n### request.cookie\n\nFunction that creates a new cookie.\n\n```javascript\nrequest.cookie('cookie_string_here')\n```\n### request.jar\n\nFunction that creates a new cookie jar.\n\n```javascript\nrequest.jar()\n```\n\n\n## Examples:\n\n```javascript\n var request = require('request')\n , rand = Math.floor(Math.random()*100000000).toString()\n ;\n request(\n { method: 'PUT'\n , uri: 'http://mikeal.iriscouch.com/testjs/' + rand\n , multipart: \n [ { 'content-type': 'application/json'\n , body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})\n }\n , { body: 'I am an attachment' }\n ] \n }\n , function (error, response, body) {\n if(response.statusCode == 201){\n console.log('document saved as: http://mikeal.iriscouch.com/testjs/'+ rand)\n } else {\n console.log('error: '+ response.statusCode)\n console.log(body)\n }\n }\n )\n```\nCookies are enabled by default (so they can be used in subsequent requests). To disable cookies set jar to false (either in defaults or in the options sent).\n\n```javascript\nvar request = request.defaults({jar: false})\nrequest('http://www.google.com', function () {\n request('http://images.google.com')\n})\n```\n\nIf you to use a custom cookie jar (instead of letting request use its own global cookie jar) you do so by setting the jar default or by specifying it as an option:\n\n```javascript\nvar j = request.jar()\nvar request = request.defaults({jar:j})\nrequest('http://www.google.com', function () {\n request('http://images.google.com')\n})\n```\nOR\n\n```javascript\nvar j = request.jar()\nvar cookie = request.cookie('your_cookie_here')\nj.add(cookie)\nrequest({url: 'http://www.google.com', jar: j}, function () {\n request('http://images.google.com')\n})\n```\n", + "readmeFilename": "README.md", + "_id": "request@2.16.6", + "_from": "request@latest" } diff --git a/node_modules/request/tests/googledoodle.png b/node_modules/request/tests/googledoodle.jpg Binary files differindex f80c9c52d..f80c9c52d 100644 --- a/node_modules/request/tests/googledoodle.png +++ b/node_modules/request/tests/googledoodle.jpg diff --git a/node_modules/request/tests/run.js b/node_modules/request/tests/run.js index f3a30d354..e717f02a3 100644 --- a/node_modules/request/tests/run.js +++ b/node_modules/request/tests/run.js @@ -1,39 +1,40 @@ var spawn = require('child_process').spawn , exitCode = 0 + , timeout = 10000 + , fs = require('fs') ; -var tests = [ - 'test-body.js' - , 'test-cookie.js' - , 'test-cookiejar.js' - , 'test-defaults.js' - , 'test-errors.js' - , 'test-headers.js' - , 'test-httpModule.js' - , 'test-https.js' - , 'test-https-strict.js' - , 'test-oauth.js' - , 'test-pipes.js' - , 'test-pool.js' - , 'test-proxy.js' - , 'test-qs.js' - , 'test-redirect.js' - , 'test-timeout.js' - , 'test-toJSON.js' - , 'test-tunnel.js' -] - -var next = function () { - if (tests.length === 0) process.exit(exitCode); - - var file = tests.shift() - console.log(file) - var proc = spawn('node', [ 'tests/' + file ]) - proc.stdout.pipe(process.stdout) - proc.stderr.pipe(process.stderr) - proc.on('exit', function (code) { - exitCode += code || 0 - next() - }) -} -next() +fs.readdir(__dirname, function (e, files) { + if (e) throw e + + var tests = files.filter(function (f) {return f.slice(0, 'test-'.length) === 'test-'}) + + var next = function () { + if (tests.length === 0) process.exit(exitCode); + + var file = tests.shift() + console.log(file) + var proc = spawn('node', [ 'tests/' + file ]) + + var killed = false + var t = setTimeout(function () { + proc.kill() + exitCode += 1 + console.error(file + ' timeout') + killed = true + }, timeout) + + proc.stdout.pipe(process.stdout) + proc.stderr.pipe(process.stderr) + proc.on('exit', function (code) { + if (code && !killed) console.error(file + ' failed') + exitCode += code || 0 + clearTimeout(t) + next() + }) + } + next() + +}) + + diff --git a/node_modules/request/tests/server.js b/node_modules/request/tests/server.js index 5b7cb511f..b6eacbadc 100644 --- a/node_modules/request/tests/server.js +++ b/node_modules/request/tests/server.js @@ -46,7 +46,7 @@ exports.createPostStream = function (text) { setTimeout(function () {postStream.emit('data', new Buffer(text)); postStream.emit('end')}, 0); return postStream; } -exports.createPostValidator = function (text) { +exports.createPostValidator = function (text, reqContentType) { var l = function (req, resp) { var r = ''; req.on('data', function (chunk) {r += chunk}) @@ -57,6 +57,10 @@ exports.createPostValidator = function (text) { } if (r !== text) console.log(r, text); assert.equal(r, text) + if (reqContentType) { + assert.ok(req.headers['content-type']) + assert.ok(~req.headers['content-type'].indexOf(reqContentType)) + } resp.writeHead(200, {'content-type':'text/plain'}) resp.write('OK') resp.end() diff --git a/node_modules/request/tests/test-basic-auth.js b/node_modules/request/tests/test-basic-auth.js new file mode 100644 index 000000000..19bb5437e --- /dev/null +++ b/node_modules/request/tests/test-basic-auth.js @@ -0,0 +1,74 @@ +var assert = require('assert') + , http = require('http') + , request = require('../index') + ; + +var numBasicRequests = 0; + +var basicServer = http.createServer(function (req, res) { + console.error('Basic auth server: ', req.method, req.url); + numBasicRequests++; + + var ok; + + if (req.headers.authorization) { + if (req.headers.authorization == 'Basic ' + new Buffer('test:testing2').toString('base64')) { + ok = true; + } else { + // Bad auth header, don't send back WWW-Authenticate header + ok = false; + } + } else { + // No auth header, send back WWW-Authenticate header + ok = false; + res.setHeader('www-authenticate', 'Basic realm="Private"'); + } + + if (ok) { + console.log('request ok'); + res.end('ok'); + } else { + console.log('status=401'); + res.statusCode = 401; + res.end('401'); + } +}); + +basicServer.listen(6767); + +request({ + 'method': 'GET', + 'uri': 'http://localhost:6767/test/', + 'auth': { + 'user': 'test', + 'pass': 'testing2', + 'sendImmediately': false + } +}, function(error, response, body) { + assert.equal(response.statusCode, 200); + assert.equal(numBasicRequests, 2); + + // If we don't set sendImmediately = false, request will send basic auth + request({ + 'method': 'GET', + 'uri': 'http://localhost:6767/test2/', + 'auth': { + 'user': 'test', + 'pass': 'testing2' + } + }, function(error, response, body) { + assert.equal(response.statusCode, 200); + assert.equal(numBasicRequests, 3); + + request({ + 'method': 'GET', + 'uri': 'http://test:testing2@localhost:6767/test2/' + }, function(error, response, body) { + assert.equal(response.statusCode, 200); + assert.equal(numBasicRequests, 4); + + console.log('All tests passed'); + basicServer.close(); + }); + }); +}); diff --git a/node_modules/request/tests/test-body.js b/node_modules/request/tests/test-body.js index a624397d7..186de123f 100644 --- a/node_modules/request/tests/test-body.js +++ b/node_modules/request/tests/test-body.js @@ -2,7 +2,7 @@ var server = require('./server') , events = require('events') , stream = require('stream') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') ; var s = server.createServer(); @@ -35,6 +35,11 @@ var tests = , encoding: 'hex' , expectBody: "efa3bfcea9e29883" } + , testGetUTF8: + { resp: server.createGetResponse(new Buffer([0xEF, 0xBB, 0xBF, 226, 152, 131])) + , encoding: "utf8" + , expectBody: "☃" + } , testGetJSON : { resp : server.createGetResponse('{"test":true}', 'application/json') , json : true diff --git a/node_modules/request/tests/test-defaults.js b/node_modules/request/tests/test-defaults.js index 479abf233..f6c402460 100644 --- a/node_modules/request/tests/test-defaults.js +++ b/node_modules/request/tests/test-defaults.js @@ -1,6 +1,6 @@ var server = require('./server') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') ; var s = server.createServer(); @@ -23,7 +23,7 @@ s.listen(s.port, function () { s.on('/post', function (req, resp) { assert.equal(req.headers.foo, 'bar'); - assert.equal(req.headers['content-type'], 'application/json'); + assert.equal(req.headers['content-type'], null); assert.equal(req.method, 'POST') resp.writeHead(200, {'Content-Type': 'application/json'}); resp.end(JSON.stringify({foo:'bar'})); @@ -36,6 +36,36 @@ s.listen(s.port, function () { counter += 1; }); + s.on('/patch', function (req, resp) { + assert.equal(req.headers.foo, 'bar'); + assert.equal(req.headers['content-type'], null); + assert.equal(req.method, 'PATCH') + resp.writeHead(200, {'Content-Type': 'application/json'}); + resp.end(JSON.stringify({foo:'bar'})); + }); + + // test post(string, object, function) + request.defaults({headers:{foo:"bar"}}).patch(s.url + '/patch', {json: true}, function (e, r, b){ + if (e) throw e; + assert.deepEqual('bar', b.foo); + counter += 1; + }); + + s.on('/post-body', function (req, resp) { + assert.equal(req.headers.foo, 'bar'); + assert.equal(req.headers['content-type'], 'application/json'); + assert.equal(req.method, 'POST') + resp.writeHead(200, {'Content-Type': 'application/json'}); + resp.end(JSON.stringify({foo:'bar'})); + }); + + // test post(string, object, function) with body + request.defaults({headers:{foo:"bar"}}).post(s.url + '/post-body', {json: true, body:{bar:"baz"}}, function (e, r, b){ + if (e) throw e; + assert.deepEqual('bar', b.foo); + counter += 1; + }); + s.on('/del', function (req, resp) { assert.equal(req.headers.foo, 'bar'); assert.equal(req.method, 'DELETE') diff --git a/node_modules/request/tests/test-digest-auth.js b/node_modules/request/tests/test-digest-auth.js new file mode 100644 index 000000000..5f2d6eb7d --- /dev/null +++ b/node_modules/request/tests/test-digest-auth.js @@ -0,0 +1,69 @@ +var assert = require('assert') + , http = require('http') + , request = require('../index') + ; + +// Test digest auth +// Using header values captured from interaction with Apache + +var numDigestRequests = 0; + +var digestServer = http.createServer(function (req, res) { + console.error('Digest auth server: ', req.method, req.url); + numDigestRequests++; + + var ok; + + if (req.headers.authorization) { + if (req.headers.authorization == 'Digest username="test", realm="Private", nonce="WpcHS2/TBAA=dffcc0dbd5f96d49a5477166649b7c0ae3866a93", uri="/test/", qop="auth", response="54753ce37c10cb20b09b769f0bed730e", nc="1", cnonce=""') { + ok = true; + } else { + // Bad auth header, don't send back WWW-Authenticate header + ok = false; + } + } else { + // No auth header, send back WWW-Authenticate header + ok = false; + res.setHeader('www-authenticate', 'Digest realm="Private", nonce="WpcHS2/TBAA=dffcc0dbd5f96d49a5477166649b7c0ae3866a93", algorithm=MD5, qop="auth"'); + } + + if (ok) { + console.log('request ok'); + res.end('ok'); + } else { + console.log('status=401'); + res.statusCode = 401; + res.end('401'); + } +}); + +digestServer.listen(6767); + +request({ + 'method': 'GET', + 'uri': 'http://localhost:6767/test/', + 'auth': { + 'user': 'test', + 'pass': 'testing', + 'sendImmediately': false + } +}, function(error, response, body) { + assert.equal(response.statusCode, 200); + assert.equal(numDigestRequests, 2); + + // If we don't set sendImmediately = false, request will send basic auth + request({ + 'method': 'GET', + 'uri': 'http://localhost:6767/test/', + 'auth': { + 'user': 'test', + 'pass': 'testing' + } + }, function(error, response, body) { + assert.equal(response.statusCode, 401); + assert.equal(numDigestRequests, 3); + + console.log('All tests passed'); + digestServer.close(); + }); +}); diff --git a/node_modules/request/tests/test-errors.js b/node_modules/request/tests/test-errors.js index 1986a59ee..4df1302a0 100644 --- a/node_modules/request/tests/test-errors.js +++ b/node_modules/request/tests/test-errors.js @@ -1,7 +1,7 @@ var server = require('./server') , events = require('events') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') ; var local = 'http://localhost:8888/asdf' diff --git a/node_modules/request/tests/test-follow-all-303.js b/node_modules/request/tests/test-follow-all-303.js index 5eec49768..956e386d1 100644 --- a/node_modules/request/tests/test-follow-all-303.js +++ b/node_modules/request/tests/test-follow-all-303.js @@ -1,4 +1,4 @@ -var request = require('request'); +var request = require('../index'); var http = require('http'); var requests = 0; var assert = require('assert'); diff --git a/node_modules/request/tests/test-follow-all.js b/node_modules/request/tests/test-follow-all.js index 4dbde6145..035d6326f 100644 --- a/node_modules/request/tests/test-follow-all.js +++ b/node_modules/request/tests/test-follow-all.js @@ -1,4 +1,4 @@ -var request = require('request'); +var request = require('../index'); var http = require('http'); var requests = 0; var assert = require('assert'); diff --git a/node_modules/request/tests/test-form.js b/node_modules/request/tests/test-form.js new file mode 100644 index 000000000..91b9230d4 --- /dev/null +++ b/node_modules/request/tests/test-form.js @@ -0,0 +1,79 @@ +var assert = require('assert') +var http = require('http'); +var path = require('path'); +var mime = require('mime'); +var request = require('../index'); +var fs = require('fs'); + +var remoteFile = 'http://nodejs.org/images/logo.png'; + +var FIELDS = [ + {name: 'my_field', value: 'my_value'}, + {name: 'my_buffer', value: new Buffer([1, 2, 3])}, + {name: 'my_file', value: fs.createReadStream(__dirname + '/unicycle.jpg')}, + {name: 'remote_file', value: request(remoteFile) } +]; + +var server = http.createServer(function(req, res) { + + // temp workaround + var data = ''; + req.setEncoding('utf8'); + + req.on('data', function(d) { + data += d; + }); + + req.on('end', function() { + // check for the fields' traces + + // 1st field : my_field + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 2nd field : my_buffer + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf(field.value) != -1 ); + + // 3rd field : my_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 ); + // check for unicycle.jpg traces + assert.ok( data.indexOf('2005:06:21 01:44:12') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(field.value.path) ) != -1 ); + + // 4th field : remote_file + var field = FIELDS.shift(); + assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 ); + assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 ); + // check for http://nodejs.org/images/logo.png traces + assert.ok( data.indexOf('ImageReady') != -1 ); + assert.ok( data.indexOf('Content-Type: '+mime.lookup(remoteFile) ) != -1 ); + + res.writeHead(200); + res.end('done'); + + }); + + +}); + +server.listen(8080, function() { + + var req = request.post('http://localhost:8080/upload', function () { + server.close(); + }) + var form = req.form() + + FIELDS.forEach(function(field) { + form.append(field.name, field.value); + }); + +}); + +process.on('exit', function() { + assert.strictEqual(FIELDS.length, 0); +}); diff --git a/node_modules/request/tests/test-hawk.js b/node_modules/request/tests/test-hawk.js new file mode 100755 index 000000000..845462580 --- /dev/null +++ b/node_modules/request/tests/test-hawk.js @@ -0,0 +1,33 @@ +var createServer = require('http').createServer + , request = require('../index') + , hawk = require('hawk') + , assert = require('assert') + ; + +var server = createServer(function (req, resp) { + + var getCred = function (id, callback) { + assert.equal(id, 'dh37fgj492je') + var credentials = + { key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn' + , algorithm: 'sha256' + , user: 'Steve' + } + return callback(null, credentials) + } + + hawk.server.authenticate(req, getCred, {}, function (err, credentials, attributes) { + resp.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' }) + resp.end(!err ? 'Hello ' + credentials.user : 'Shoosh!') + }) + +}) + +server.listen(8080, function () { + var creds = {key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn', algorithm: 'sha256', id:'dh37fgj492je'} + request('http://localhost:8080', {hawk:{credentials:creds}}, function (e, r, b) { + assert.equal(200, r.statusCode) + assert.equal(b, 'Hello Steve') + server.close() + }) +})
\ No newline at end of file diff --git a/node_modules/request/tests/test-headers.js b/node_modules/request/tests/test-headers.js index 31fe3f4e8..3982b9be0 100644 --- a/node_modules/request/tests/test-headers.js +++ b/node_modules/request/tests/test-headers.js @@ -1,8 +1,8 @@ var server = require('./server') , assert = require('assert') - , request = require('../main.js') - , Cookie = require('../vendor/cookie') - , Jar = require('../vendor/cookie/jar') + , request = require('../index') + , Cookie = require('cookie-jar') + , Jar = Cookie.Jar , s = server.createServer() s.listen(s.port, function () { diff --git a/node_modules/request/tests/test-httpModule.js b/node_modules/request/tests/test-httpModule.js index 1866de2fa..2c19615f7 100644 --- a/node_modules/request/tests/test-httpModule.js +++ b/node_modules/request/tests/test-httpModule.js @@ -2,7 +2,7 @@ var http = require('http') , https = require('https') , server = require('./server') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') var faux_requests_made = {'http':0, 'https':0} @@ -63,14 +63,14 @@ function run_tests(httpModules) { var to_https = 'http://localhost:'+plain_server.port+'/to_https' var to_plain = 'https://localhost:'+https_server.port+'/to_plain' - request(to_https, {'httpModules':httpModules}, function (er, res, body) { - assert.ok(!er, 'Bounce to SSL worked') + request(to_https, {'httpModules':httpModules, strictSSL:false}, function (er, res, body) { + if (er) throw er assert.equal(body, 'https', 'Received HTTPS server body') done() }) - request(to_plain, {'httpModules':httpModules}, function (er, res, body) { - assert.ok(!er, 'Bounce to plaintext server worked') + request(to_plain, {'httpModules':httpModules, strictSSL:false}, function (er, res, body) { + if (er) throw er assert.equal(body, 'plain', 'Received HTTPS server body') done() }) diff --git a/node_modules/request/tests/test-https-strict.js b/node_modules/request/tests/test-https-strict.js index 470b68ddd..d49a9afcb 100644 --- a/node_modules/request/tests/test-https-strict.js +++ b/node_modules/request/tests/test-https-strict.js @@ -3,7 +3,7 @@ var server = require('./server') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') , fs = require('fs') , path = require('path') , opts = { key: path.resolve(__dirname, 'ssl/ca/server.key') diff --git a/node_modules/request/tests/test-https.js b/node_modules/request/tests/test-https.js index 58e7db93f..b6858d433 100644 --- a/node_modules/request/tests/test-https.js +++ b/node_modules/request/tests/test-https.js @@ -1,6 +1,6 @@ var server = require('./server') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') var s = server.createSSLServer(); @@ -69,6 +69,7 @@ s.listen(s.port, function () { var test = tests[i] s.on('/'+i, test.resp) test.uri = s.url + '/' + i + test.rejectUnauthorized = false request(test, function (err, resp, body) { if (err) throw err if (test.expectBody) { diff --git a/node_modules/request/tests/test-oauth.js b/node_modules/request/tests/test-oauth.js index 72ca92333..3269483d8 100644 --- a/node_modules/request/tests/test-oauth.js +++ b/node_modules/request/tests/test-oauth.js @@ -1,7 +1,7 @@ -var hmacsign = require('../oauth').hmacsign +var hmacsign = require('oauth-sign').hmacsign , assert = require('assert') , qs = require('querystring') - , request = require('../main') + , request = require('../index') ; function getsignature (r) { diff --git a/node_modules/request/tests/test-params.js b/node_modules/request/tests/test-params.js index 5ddb31162..a5831a140 100644 --- a/node_modules/request/tests/test-params.js +++ b/node_modules/request/tests/test-params.js @@ -1,6 +1,6 @@ var server = require('./server') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') ; var s = server.createServer(); @@ -82,7 +82,8 @@ s.listen(s.port, function () { } counter = counter - 1; if (counter === 0) { - console.log(Object.keys(tests).length+" tests passed.") + assert.notEqual(typeof test.callback, 'function') + console.log(1 + Object.keys(tests).length+" tests passed.") s.close() } }) diff --git a/node_modules/request/tests/test-piped-redirect.js b/node_modules/request/tests/test-piped-redirect.js new file mode 100644 index 000000000..e295ec7fa --- /dev/null +++ b/node_modules/request/tests/test-piped-redirect.js @@ -0,0 +1,42 @@ +var http = require('http') + , assert = require('assert') + , request = require('../index') + ; + +var portOne = 8968 + , portTwo = 8969 + ; + + +// server one +var s1 = http.createServer(function (req, resp) { + if (req.url == '/original') { + resp.writeHeader(302, {'location': '/redirected'}) + resp.end() + } else if (req.url == '/redirected') { + resp.writeHeader(200, {'content-type': 'text/plain'}) + resp.write('OK') + resp.end() + } + +}).listen(portOne); + + +// server two +var s2 = http.createServer(function (req, resp) { + var x = request('http://localhost:'+portOne+'/original') + req.pipe(x) + x.pipe(resp) + +}).listen(portTwo, function () { + var r = request('http://localhost:'+portTwo+'/original', function (err, res, body) { + assert.equal(body, 'OK') + + s1.close() + s2.close() + }); + + // it hangs, so wait a second :) + r.timeout = 1000; + +}) diff --git a/node_modules/request/tests/test-pipes.js b/node_modules/request/tests/test-pipes.js index 186987445..52a15cc7e 100644 --- a/node_modules/request/tests/test-pipes.js +++ b/node_modules/request/tests/test-pipes.js @@ -3,7 +3,7 @@ var server = require('./server') , stream = require('stream') , assert = require('assert') , fs = require('fs') - , request = require('../main.js') + , request = require('../index') , path = require('path') , util = require('util') ; @@ -58,6 +58,20 @@ s.listen(s.port, function () { mydata.emit('data', 'mydata'); mydata.emit('end'); + // Test pipeing to a request object with a json body + s.once('/push-json', server.createPostValidator("{\"foo\":\"bar\"}", "application/json")); + + var mybodydata = new stream.Stream(); + mybodydata.readable = true + + counter++ + var r2 = request.put({url:'http://localhost:3453/push-json',json:true}, function () { + check(); + }) + mybodydata.pipe(r2) + + mybodydata.emit('data', JSON.stringify({foo:"bar"})); + mybodydata.emit('end'); // Test pipeing from a request object. s.once('/pull', server.createGetResponse("mypulldata")); @@ -99,7 +113,7 @@ s.listen(s.port, function () { }) s.on('/pushjs', function (req, resp) { if (req.method === "PUT") { - assert.equal(req.headers['content-type'], 'text/javascript'); + assert.equal(req.headers['content-type'], 'application/javascript'); check(); } }) @@ -110,8 +124,8 @@ s.listen(s.port, function () { if (req.headers['x-oneline-proxy']) { resp.setHeader('x-oneline-proxy', 'yup') } - resp.writeHead('200', {'content-type':'image/png'}) - fs.createReadStream(path.join(__dirname, 'googledoodle.png')).pipe(resp) + resp.writeHead('200', {'content-type':'image/jpeg'}) + fs.createReadStream(path.join(__dirname, 'googledoodle.jpg')).pipe(resp) }) s.on('/onelineproxy', function (req, resp) { var x = request('http://localhost:3453/doodle') @@ -132,18 +146,18 @@ s.listen(s.port, function () { check(); }) - var doodleWrite = fs.createWriteStream(path.join(__dirname, 'test.png')) + var doodleWrite = fs.createWriteStream(path.join(__dirname, 'test.jpg')) counter++ request.get('http://localhost:3453/doodle').pipe(doodleWrite) doodleWrite.on('close', function () { - assert.deepEqual(fs.readFileSync(path.join(__dirname, 'googledoodle.png')), fs.readFileSync(path.join(__dirname, 'test.png'))) + assert.deepEqual(fs.readFileSync(path.join(__dirname, 'googledoodle.jpg')), fs.readFileSync(path.join(__dirname, 'test.jpg'))) check() }) process.on('exit', function () { - fs.unlinkSync(path.join(__dirname, 'test.png')) + fs.unlinkSync(path.join(__dirname, 'test.jpg')) }) counter++ diff --git a/node_modules/request/tests/test-pool.js b/node_modules/request/tests/test-pool.js index 1e7d5786a..791ee8b93 100644 --- a/node_modules/request/tests/test-pool.js +++ b/node_modules/request/tests/test-pool.js @@ -1,4 +1,4 @@ -var request = require('../main') +var request = require('../index') , http = require('http') , assert = require('assert') ; diff --git a/node_modules/request/tests/test-protocol-changing-redirect.js b/node_modules/request/tests/test-protocol-changing-redirect.js index f74e19680..7e83a41bd 100644 --- a/node_modules/request/tests/test-protocol-changing-redirect.js +++ b/node_modules/request/tests/test-protocol-changing-redirect.js @@ -1,6 +1,6 @@ var server = require('./server') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') var s = server.createServer() @@ -51,7 +51,8 @@ for (var i = 0; i < 5; i ++) { var val = 'test_' + i expect[val] = true request({ url: (i % 2 ? sUrl : ssUrl) + '/a' - , headers: { 'x-test-key': val } }) + , headers: { 'x-test-key': val } + , rejectUnauthorized: false }) } function done () { diff --git a/node_modules/request/tests/test-proxy.js b/node_modules/request/tests/test-proxy.js index 647157cae..e183d68d1 100644 --- a/node_modules/request/tests/test-proxy.js +++ b/node_modules/request/tests/test-proxy.js @@ -3,7 +3,7 @@ var server = require('./server') , stream = require('stream') , assert = require('assert') , fs = require('fs') - , request = require('../main.js') + , request = require('../index') , path = require('path') , util = require('util') ; diff --git a/node_modules/request/tests/test-qs.js b/node_modules/request/tests/test-qs.js index 1aac22bc9..f81a8df90 100644 --- a/node_modules/request/tests/test-qs.js +++ b/node_modules/request/tests/test-qs.js @@ -1,4 +1,4 @@ -var request = request = require('../main.js') +var request = request = require('../index') , assert = require('assert') ; @@ -26,3 +26,9 @@ var req4 = request.get({ uri: 'http://www.google.com?x=y'}) setTimeout(function() { assert.equal('/?x=y', req4.path) }, 1) + +// Test giving empty qs property +var req5 = request.get({ uri: 'http://www.google.com', qs: {}}) +setTimeout(function(){ + assert.equal('/', req5.path) +}, 1) diff --git a/node_modules/request/tests/test-redirect.js b/node_modules/request/tests/test-redirect.js index b84844a79..cdd460666 100644 --- a/node_modules/request/tests/test-redirect.js +++ b/node_modules/request/tests/test-redirect.js @@ -1,8 +1,9 @@ var server = require('./server') , assert = require('assert') - , request = require('../main.js') - , Cookie = require('../vendor/cookie') - , Jar = require('../vendor/cookie/jar') + , request = require('../index') + , Cookie = require('cookie-jar') + , Jar = Cookie.Jar + ; var s = server.createServer() diff --git a/node_modules/request/tests/test-s3.js b/node_modules/request/tests/test-s3.js new file mode 100644 index 000000000..0f6a832b6 --- /dev/null +++ b/node_modules/request/tests/test-s3.js @@ -0,0 +1,13 @@ +var request = require('../index') + +var r = request.get('https://log.curlybracecast.com.s3.amazonaws.com/', + { aws: + { key: 'AKIAI6KIQRRVMGK3WK5Q' + , secret: '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' + , bucket: 'log.curlybracecast.com' + } + }, function (e, resp, body) { + console.log(r.headers) + console.log(body) + } +)
\ No newline at end of file diff --git a/node_modules/request/tests/test-timeout.js b/node_modules/request/tests/test-timeout.js index 673f8ad86..70363670f 100644 --- a/node_modules/request/tests/test-timeout.js +++ b/node_modules/request/tests/test-timeout.js @@ -2,7 +2,7 @@ var server = require('./server') , events = require('events') , stream = require('stream') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') ; var s = server.createServer(); diff --git a/node_modules/request/tests/test-toJSON.js b/node_modules/request/tests/test-toJSON.js index b7c67effc..6d5f92aaa 100644 --- a/node_modules/request/tests/test-toJSON.js +++ b/node_modules/request/tests/test-toJSON.js @@ -1,4 +1,4 @@ -var request = require('../main') +var request = require('../index') , http = require('http') , assert = require('assert') ; diff --git a/node_modules/request/tests/test-tunnel.js b/node_modules/request/tests/test-tunnel.js index 51e2126f8..2f7934dff 100644 --- a/node_modules/request/tests/test-tunnel.js +++ b/node_modules/request/tests/test-tunnel.js @@ -6,7 +6,7 @@ var server = require('./server') , assert = require('assert') - , request = require('../main.js') + , request = require('../index') , fs = require('fs') , path = require('path') , caFile = path.resolve(__dirname, 'ssl/npm-ca.crt') @@ -23,7 +23,7 @@ var ready = false squid.stderr.on('data', function (c) { console.error('SQUIDERR ' + c.toString().trim().split('\n') .join('\nSQUIDERR ')) - ready = c.toString().match(/ready to serve requests/i) + ready = c.toString().match(/ready to serve requests|Accepting HTTP Socket connections/i) }) squid.stdout.on('data', function (c) { diff --git a/node_modules/request/tests/unicycle.jpg b/node_modules/request/tests/unicycle.jpg Binary files differnew file mode 100644 index 000000000..7cea4dd71 --- /dev/null +++ b/node_modules/request/tests/unicycle.jpg diff --git a/node_modules/request/tunnel.js b/node_modules/request/tunnel.js deleted file mode 100644 index 469c130e8..000000000 --- a/node_modules/request/tunnel.js +++ /dev/null @@ -1,230 +0,0 @@ -'use strict'; - -var net = require('net'); -var tls = require('tls'); -var http = require('http'); -var https = require('https'); -var events = require('events'); -var assert = require('assert'); -var util = require('util'); - - -exports.httpOverHttp = httpOverHttp; -exports.httpsOverHttp = httpsOverHttp; -exports.httpOverHttps = httpOverHttps; -exports.httpsOverHttps = httpsOverHttps; - - -function httpOverHttp(options) { - var agent = new TunnelingAgent(options); - agent.request = http.request; - return agent; -} - -function httpsOverHttp(options) { - var agent = new TunnelingAgent(options); - agent.request = http.request; - agent.createSocket = createSecureSocket; - return agent; -} - -function httpOverHttps(options) { - var agent = new TunnelingAgent(options); - agent.request = https.request; - return agent; -} - -function httpsOverHttps(options) { - var agent = new TunnelingAgent(options); - agent.request = https.request; - agent.createSocket = createSecureSocket; - return agent; -} - - -function TunnelingAgent(options) { - var self = this; - self.options = options || {}; - self.proxyOptions = self.options.proxy || {}; - self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets; - self.requests = []; - self.sockets = []; - - self.on('free', function onFree(socket, host, port) { - for (var i = 0, len = self.requests.length; i < len; ++i) { - var pending = self.requests[i]; - if (pending.host === host && pending.port === port) { - // Detect the request to connect same origin server, - // reuse the connection. - self.requests.splice(i, 1); - pending.request.onSocket(socket); - return; - } - } - socket.destroy(); - self.removeSocket(socket); - }); -} -util.inherits(TunnelingAgent, events.EventEmitter); - -TunnelingAgent.prototype.addRequest = function addRequest(req, host, port) { - var self = this; - - if (self.sockets.length >= this.maxSockets) { - // We are over limit so we'll add it to the queue. - self.requests.push({host: host, port: port, request: req}); - return; - } - - // If we are under maxSockets create a new one. - self.createSocket({host: host, port: port, request: req}, function(socket) { - socket.on('free', onFree); - socket.on('close', onCloseOrRemove); - socket.on('agentRemove', onCloseOrRemove); - req.onSocket(socket); - - function onFree() { - self.emit('free', socket, host, port); - } - - function onCloseOrRemove(err) { - self.removeSocket(); - socket.removeListener('free', onFree); - socket.removeListener('close', onCloseOrRemove); - socket.removeListener('agentRemove', onCloseOrRemove); - } - }); -}; - -TunnelingAgent.prototype.createSocket = function createSocket(options, cb) { - var self = this; - var placeholder = {}; - self.sockets.push(placeholder); - - var connectOptions = mergeOptions({}, self.proxyOptions, { - method: 'CONNECT', - path: options.host + ':' + options.port, - agent: false - }); - if (connectOptions.proxyAuth) { - connectOptions.headers = connectOptions.headers || {}; - connectOptions.headers['Proxy-Authorization'] = 'Basic ' + - new Buffer(connectOptions.proxyAuth).toString('base64'); - } - - debug('making CONNECT request'); - var connectReq = self.request(connectOptions); - connectReq.useChunkedEncodingByDefault = false; // for v0.6 - connectReq.once('response', onResponse); // for v0.6 - connectReq.once('upgrade', onUpgrade); // for v0.6 - connectReq.once('connect', onConnect); // for v0.7 or later - connectReq.once('error', onError); - connectReq.end(); - - function onResponse(res) { - // Very hacky. This is necessary to avoid http-parser leaks. - res.upgrade = true; - } - - function onUpgrade(res, socket, head) { - // Hacky. - process.nextTick(function() { - onConnect(res, socket, head); - }); - } - - function onConnect(res, socket, head) { - connectReq.removeAllListeners(); - socket.removeAllListeners(); - - if (res.statusCode === 200) { - assert.equal(head.length, 0); - debug('tunneling connection has established'); - self.sockets[self.sockets.indexOf(placeholder)] = socket; - cb(socket); - } else { - debug('tunneling socket could not be established, statusCode=%d', - res.statusCode); - var error = new Error('tunneling socket could not be established, ' + - 'sutatusCode=' + res.statusCode); - error.code = 'ECONNRESET'; - options.request.emit('error', error); - self.removeSocket(placeholder); - } - } - - function onError(cause) { - connectReq.removeAllListeners(); - - debug('tunneling socket could not be established, cause=%s\n', - cause.message, cause.stack); - var error = new Error('tunneling socket could not be established, ' + - 'cause=' + cause.message); - error.code = 'ECONNRESET'; - options.request.emit('error', error); - self.removeSocket(placeholder); - } -}; - -TunnelingAgent.prototype.removeSocket = function removeSocket(socket) { - var pos = this.sockets.indexOf(socket) - if (pos === -1) { - return; - } - this.sockets.splice(pos, 1); - - var pending = this.requests.shift(); - if (pending) { - // If we have pending requests and a socket gets closed a new one - // needs to be created to take over in the pool for the one that closed. - this.createSocket(pending, function(socket) { - pending.request.onSocket(socket); - }); - } -}; - -function createSecureSocket(options, cb) { - var self = this; - TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { - // 0 is dummy port for v0.6 - var secureSocket = tls.connect(0, mergeOptions({}, self.options, { - servername: options.host, - socket: socket - })); - cb(secureSocket); - }); -} - - -function mergeOptions(target) { - for (var i = 1, len = arguments.length; i < len; ++i) { - var overrides = arguments[i]; - if (typeof overrides === 'object') { - var keys = Object.keys(overrides); - for (var j = 0, keyLen = keys.length; j < keyLen; ++j) { - var k = keys[j]; - if (overrides[k] !== undefined) { - target[k] = overrides[k]; - } - } - } - } - return target; -} - - -var debug; -if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { - debug = function() { - var args = Array.prototype.slice.call(arguments); - if (typeof args[0] === 'string') { - args[0] = 'TUNNEL: ' + args[0]; - } else { - args.unshift('TUNNEL:'); - } - console.error.apply(console, args); - } -} else { - debug = function() {}; -} -exports.debug = debug; // for test diff --git a/node_modules/request/uuid.js b/node_modules/request/uuid.js deleted file mode 100644 index 1d83bd50a..000000000 --- a/node_modules/request/uuid.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = function () { - var s = [], itoh = '0123456789ABCDEF'; - - // Make array of random hex digits. The UUID only has 32 digits in it, but we - // allocate an extra items to make room for the '-'s we'll be inserting. - for (var i = 0; i <36; i++) s[i] = Math.floor(Math.random()*0x10); - - // Conform to RFC-4122, section 4.4 - s[14] = 4; // Set 4 high bits of time_high field to version - s[19] = (s[19] & 0x3) | 0x8; // Specify 2 high bits of clock sequence - - // Convert to hex chars - for (var i = 0; i <36; i++) s[i] = itoh[s[i]]; - - // Insert '-'s - s[8] = s[13] = s[18] = s[23] = '-'; - - return s.join(''); -} |