diff --git a/NodeDrawing/app.js b/NodeDrawing/app.js new file mode 100644 index 0000000..f8ba2f3 --- /dev/null +++ b/NodeDrawing/app.js @@ -0,0 +1,38 @@ + +/** + * Module dependencies. + */ + +var express = require('express'); + +var app = module.exports = express.createServer(); + +// Configuration + +app.configure(function(){ + app.set('views', __dirname + '/views'); + app.set('view engine', 'jade'); + app.use(express.bodyParser()); + app.use(express.methodOverride()); + app.use(app.router); + app.use(express.static(__dirname + '/public')); +}); + +app.configure('development', function(){ + app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); +}); + +app.configure('production', function(){ + app.use(express.errorHandler()); +}); + +// Routes + +app.get('/', function(req, res){ + res.render('index', { + title: 'Express' + }); +}); + +app.listen(3000); +console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env); diff --git a/NodeDrawing/node_modules/.bin/express b/NodeDrawing/node_modules/.bin/express new file mode 120000 index 0000000..b741d99 --- /dev/null +++ b/NodeDrawing/node_modules/.bin/express @@ -0,0 +1 @@ +../express/bin/express \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/.npmignore b/NodeDrawing/node_modules/express/.npmignore new file mode 100644 index 0000000..74bd365 --- /dev/null +++ b/NodeDrawing/node_modules/express/.npmignore @@ -0,0 +1,7 @@ +.git* +docs/ +examples/ +support/ +test/ +testing.js +.DS_Store diff --git a/NodeDrawing/node_modules/express/History.md b/NodeDrawing/node_modules/express/History.md new file mode 100644 index 0000000..3242751 --- /dev/null +++ b/NodeDrawing/node_modules/express/History.md @@ -0,0 +1,689 @@ + +2.3.12 / 2011-06-22 +================== + + * \#express is now on freenode! come join! + * Added `req.get(field, param)` + * Added links to Japanese documentation, thanks @hideyukisaito! + * Added; the `express(1)` generated app outputs the env + * Added `content-negotiation` example + * Dependency: connect >= 1.5.1 < 2.0.0 + * Fixed view layout bug. Closes #720 + * Fixed; ignore body on 304. Closes #701 + +2.3.11 / 2011-06-04 +================== + + * Added `npm test` + * Removed generation of dummy test file from `express(1)` + * Fixed; `express(1)` adds express as a dep + * Fixed; prune on `prepublish` + +2.3.10 / 2011-05-27 +================== + + * Added `req.route`, exposing the current route + * Added _package.json_ generation support to `express(1)` + * Fixed call to `app.param()` function for optional params. Closes #682 + +2.3.9 / 2011-05-25 +================== + + * Fixed bug-ish with `../' in `res.partial()` calls + +2.3.8 / 2011-05-24 +================== + + * Fixed `app.options()` + +2.3.7 / 2011-05-23 +================== + + * Added route `Collection`, ex: `app.get('/user/:id').remove();` + * Added support for `app.param(fn)` to define param logic + * Removed `app.param()` support for callback with return value + * Removed module.parent check from express(1) generated app. Closes #670 + * Refactored router. Closes #639 + +2.3.6 / 2011-05-20 +================== + + * Changed; using devDependencies instead of git submodules + * Fixed redis session example + * Fixed markdown example + * Fixed view caching, should not be enabled in development + +2.3.5 / 2011-05-20 +================== + + * Added export `.view` as alias for `.View` + +2.3.4 / 2011-05-08 +================== + + * Added `./examples/say` + * Fixed `res.sendfile()` bug preventing the transfer of files with spaces + +2.3.3 / 2011-05-03 +================== + + * Added "case sensitive routes" option. + * Changed; split methods supported per rfc [slaskis] + * Fixed route-specific middleware when using the same callback function several times + +2.3.2 / 2011-04-27 +================== + + * Fixed view hints + +2.3.1 / 2011-04-26 +================== + + * Added `app.match()` as `app.match.all()` + * Added `app.lookup()` as `app.lookup.all()` + * Added `app.remove()` for `app.remove.all()` + * Added `app.remove.VERB()` + * Fixed template caching collision issue. Closes #644 + * Moved router over from connect and started refactor + +2.3.0 / 2011-04-25 +================== + + * Added options support to `res.clearCookie()` + * Added `res.helpers()` as alias of `res.locals()` + * Added; json defaults to UTF-8 with `res.send()`. Closes #632. [Daniel * Dependency `connect >= 1.4.0` + * Changed; auto set Content-Type in res.attachement [Aaron Heckmann] + * Renamed "cache views" to "view cache". Closes #628 + * Fixed caching of views when using several apps. Closes #637 + * Fixed gotcha invoking `app.param()` callbacks once per route middleware. +Closes #638 + * Fixed partial lookup precedence. Closes #631 +Shaw] + +2.2.2 / 2011-04-12 +================== + + * Added second callback support for `res.download()` connection errors + * Fixed `filename` option passing to template engine + +2.2.1 / 2011-04-04 +================== + + * Added `layout(path)` helper to change the layout within a view. Closes #610 + * Fixed `partial()` collection object support. + Previously only anything with `.length` would work. + When `.length` is present one must still be aware of holes, + however now `{ collection: {foo: 'bar'}}` is valid, exposes + `keyInCollection` and `keysInCollection`. + + * Performance improved with better view caching + * Removed `request` and `response` locals + * Changed; errorHandler page title is now `Express` instead of `Connect` + +2.2.0 / 2011-03-30 +================== + + * Added `app.lookup.VERB()`, ex `app.lookup.put('/user/:id')`. Closes #606 + * Added `app.match.VERB()`, ex `app.match.put('/user/12')`. Closes #606 + * Added `app.VERB(path)` as alias of `app.lookup.VERB()`. + * Dependency `connect >= 1.2.0` + +2.1.1 / 2011-03-29 +================== + + * Added; expose `err.view` object when failing to locate a view + * Fixed `res.partial()` call `next(err)` when no callback is given [reported by aheckmann] + * Fixed; `res.send(undefined)` responds with 204 [aheckmann] + +2.1.0 / 2011-03-24 +================== + + * Added `/_?` partial lookup support. Closes #447 + * Added `request`, `response`, and `app` local variables + * Added `settings` local variable, containing the app's settings + * Added `req.flash()` exception if `req.session` is not available + * Added `res.send(bool)` support (json response) + * Fixed stylus example for latest version + * Fixed; wrap try/catch around `res.render()` + +2.0.0 / 2011-03-17 +================== + + * Fixed up index view path alternative. + * Changed; `res.locals()` without object returns the locals + +2.0.0rc3 / 2011-03-17 +================== + + * Added `res.locals(obj)` to compliment `res.local(key, val)` + * Added `res.partial()` callback support + * Fixed recursive error reporting issue in `res.render()` + +2.0.0rc2 / 2011-03-17 +================== + + * Changed; `partial()` "locals" are now optional + * Fixed `SlowBuffer` support. Closes #584 [reported by tyrda01] + * Fixed .filename view engine option [reported by drudge] + * Fixed blog example + * Fixed `{req,res}.app` reference when mounting [Ben Weaver] + +2.0.0rc / 2011-03-14 +================== + + * Fixed; expose `HTTPSServer` constructor + * Fixed express(1) default test charset. Closes #579 [reported by secoif] + * Fixed; default charset to utf-8 instead of utf8 for lame IE [reported by NickP] + +2.0.0beta3 / 2011-03-09 +================== + + * Added support for `res.contentType()` literal + The original `res.contentType('.json')`, + `res.contentType('application/json')`, and `res.contentType('json')` + will work now. + * Added `res.render()` status option support back + * Added charset option for `res.render()` + * Added `.charset` support (via connect 1.0.4) + * Added view resolution hints when in development and a lookup fails + * Added layout lookup support relative to the page view. + For example while rendering `./views/user/index.jade` if you create + `./views/user/layout.jade` it will be used in favour of the root layout. + * Fixed `res.redirect()`. RFC states absolute url [reported by unlink] + * Fixed; default `res.send()` string charset to utf8 + * Removed `Partial` constructor (not currently used) + +2.0.0beta2 / 2011-03-07 +================== + + * Added res.render() `.locals` support back to aid in migration process + * Fixed flash example + +2.0.0beta / 2011-03-03 +================== + + * Added HTTPS support + * Added `res.cookie()` maxAge support + * Added `req.header()` _Referrer_ / _Referer_ special-case, either works + * Added mount support for `res.redirect()`, now respects the mount-point + * Added `union()` util, taking place of `merge(clone())` combo + * Added stylus support to express(1) generated app + * Added secret to session middleware used in examples and generated app + * Added `res.local(name, val)` for progressive view locals + * Added default param support to `req.param(name, default)` + * Added `app.disabled()` and `app.enabled()` + * Added `app.register()` support for omitting leading ".", either works + * Added `res.partial()`, using the same interface as `partial()` within a view. Closes #539 + * Added `app.param()` to map route params to async/sync logic + * Added; aliased `app.helpers()` as `app.locals()`. Closes #481 + * Added extname with no leading "." support to `res.contentType()` + * Added `cache views` setting, defaulting to enabled in "production" env + * Added index file partial resolution, eg: partial('user') may try _views/user/index.jade_. + * Added `req.accepts()` support for extensions + * Changed; `res.download()` and `res.sendfile()` now utilize Connect's + static file server `connect.static.send()`. + * Changed; replaced `connect.utils.mime()` with npm _mime_ module + * Changed; allow `req.query` to be pre-defined (via middleware or other parent + * Changed view partial resolution, now relative to parent view + * Changed view engine signature. no longer `engine.render(str, options, callback)`, now `engine.compile(str, options) -> Function`, the returned function accepts `fn(locals)`. + * Fixed `req.param()` bug returning Array.prototype methods. Closes #552 + * Fixed; using `Stream#pipe()` instead of `sys.pump()` in `res.sendfile()` + * Fixed; using _qs_ module instead of _querystring_ + * Fixed; strip unsafe chars from jsonp callbacks + * Removed "stream threshold" setting + +1.0.8 / 2011-03-01 +================== + + * Allow `req.query` to be pre-defined (via middleware or other parent app) + * "connect": ">= 0.5.0 < 1.0.0". Closes #547 + * Removed the long deprecated __EXPRESS_ENV__ support + +1.0.7 / 2011-02-07 +================== + + * Fixed `render()` setting inheritance. + Mounted apps would not inherit "view engine" + +1.0.6 / 2011-02-07 +================== + + * Fixed `view engine` setting bug when period is in dirname + +1.0.5 / 2011-02-05 +================== + + * Added secret to generated app `session()` call + +1.0.4 / 2011-02-05 +================== + + * Added `qs` dependency to _package.json_ + * Fixed namespaced `require()`s for latest connect support + +1.0.3 / 2011-01-13 +================== + + * Remove unsafe characters from JSONP callback names [Ryan Grove] + +1.0.2 / 2011-01-10 +================== + + * Removed nested require, using `connect.router` + +1.0.1 / 2010-12-29 +================== + + * Fixed for middleware stacked via `createServer()` + previously the `foo` middleware passed to `createServer(foo)` + would not have access to Express methods such as `res.send()` + or props like `req.query` etc. + +1.0.0 / 2010-11-16 +================== + + * Added; deduce partial object names from the last segment. + For example by default `partial('forum/post', postObject)` will + give you the _post_ object, providing a meaningful default. + * Added http status code string representation to `res.redirect()` body + * Added; `res.redirect()` supporting _text/plain_ and _text/html_ via __Accept__. + * Added `req.is()` to aid in content negotiation + * Added partial local inheritance [suggested by masylum]. Closes #102 + providing access to parent template locals. + * Added _-s, --session[s]_ flag to express(1) to add session related middleware + * Added _--template_ flag to express(1) to specify the + template engine to use. + * Added _--css_ flag to express(1) to specify the + stylesheet engine to use (or just plain css by default). + * Added `app.all()` support [thanks aheckmann] + * Added partial direct object support. + You may now `partial('user', user)` providing the "user" local, + vs previously `partial('user', { object: user })`. + * Added _route-separation_ example since many people question ways + to do this with CommonJS modules. Also view the _blog_ example for + an alternative. + * Performance; caching view path derived partial object names + * Fixed partial local inheritance precedence. [reported by Nick Poulden] Closes #454 + * Fixed jsonp support; _text/javascript_ as per mailinglist discussion + +1.0.0rc4 / 2010-10-14 +================== + + * Added _NODE_ENV_ support, _EXPRESS_ENV_ is deprecated and will be removed in 1.0.0 + * Added route-middleware support (very helpful, see the [docs](http://expressjs.com/guide.html#Route-Middleware)) + * Added _jsonp callback_ setting to enable/disable jsonp autowrapping [Dav Glass] + * Added callback query check on response.send to autowrap JSON objects for simple webservice implementations [Dav Glass] + * Added `partial()` support for array-like collections. Closes #434 + * Added support for swappable querystring parsers + * Added session usage docs. Closes #443 + * Added dynamic helper caching. Closes #439 [suggested by maritz] + * Added authentication example + * Added basic Range support to `res.sendfile()` (and `res.download()` etc) + * Changed; `express(1)` generated app using 2 spaces instead of 4 + * Default env to "development" again [aheckmann] + * Removed _context_ option is no more, use "scope" + * Fixed; exposing _./support_ libs to examples so they can run without installs + * Fixed mvc example + +1.0.0rc3 / 2010-09-20 +================== + + * Added confirmation for `express(1)` app generation. Closes #391 + * Added extending of flash formatters via `app.flashFormatters` + * Added flash formatter support. Closes #411 + * Added streaming support to `res.sendfile()` using `sys.pump()` when >= "stream threshold" + * Added _stream threshold_ setting for `res.sendfile()` + * Added `res.send()` __HEAD__ support + * Added `res.clearCookie()` + * Added `res.cookie()` + * Added `res.render()` headers option + * Added `res.redirect()` response bodies + * Added `res.render()` status option support. Closes #425 [thanks aheckmann] + * Fixed `res.sendfile()` responding with 403 on malicious path + * Fixed `res.download()` bug; when an error occurs remove _Content-Disposition_ + * Fixed; mounted apps settings now inherit from parent app [aheckmann] + * Fixed; stripping Content-Length / Content-Type when 204 + * Fixed `res.send()` 204. Closes #419 + * Fixed multiple _Set-Cookie_ headers via `res.header()`. Closes #402 + * Fixed bug messing with error handlers when `listenFD()` is called instead of `listen()`. [thanks guillermo] + + +1.0.0rc2 / 2010-08-17 +================== + + * Added `app.register()` for template engine mapping. Closes #390 + * Added `res.render()` callback support as second argument (no options) + * Added callback support to `res.download()` + * Added callback support for `res.sendfile()` + * Added support for middleware access via `express.middlewareName()` vs `connect.middlewareName()` + * Added "partials" setting to docs + * Added default expresso tests to `express(1)` generated app. Closes #384 + * Fixed `res.sendfile()` error handling, defer via `next()` + * Fixed `res.render()` callback when a layout is used [thanks guillermo] + * Fixed; `make install` creating ~/.node_libraries when not present + * Fixed issue preventing error handlers from being defined anywhere. Closes #387 + +1.0.0rc / 2010-07-28 +================== + + * Added mounted hook. Closes #369 + * Added connect dependency to _package.json_ + + * Removed "reload views" setting and support code + development env never caches, production always caches. + + * Removed _param_ in route callbacks, signature is now + simply (req, res, next), previously (req, res, params, next). + Use _req.params_ for path captures, _req.query_ for GET params. + + * Fixed "home" setting + * Fixed middleware/router precedence issue. Closes #366 + * Fixed; _configure()_ callbacks called immediately. Closes #368 + +1.0.0beta2 / 2010-07-23 +================== + + * Added more examples + * Added; exporting `Server` constructor + * Added `Server#helpers()` for view locals + * Added `Server#dynamicHelpers()` for dynamic view locals. Closes #349 + * Added support for absolute view paths + * Added; _home_ setting defaults to `Server#route` for mounted apps. Closes #363 + * Added Guillermo Rauch to the contributor list + * Added support for "as" for non-collection partials. Closes #341 + * Fixed _install.sh_, ensuring _~/.node_libraries_ exists. Closes #362 [thanks jf] + * Fixed `res.render()` exceptions, now passed to `next()` when no callback is given [thanks guillermo] + * Fixed instanceof `Array` checks, now `Array.isArray()` + * Fixed express(1) expansion of public dirs. Closes #348 + * Fixed middleware precedence. Closes #345 + * Fixed view watcher, now async [thanks aheckmann] + +1.0.0beta / 2010-07-15 +================== + + * Re-write + - much faster + - much lighter + - Check [ExpressJS.com](http://expressjs.com) for migration guide and updated docs + +0.14.0 / 2010-06-15 +================== + + * Utilize relative requires + * Added Static bufferSize option [aheckmann] + * Fixed caching of view and partial subdirectories [aheckmann] + * Fixed mime.type() comments now that ".ext" is not supported + * Updated haml submodule + * Updated class submodule + * Removed bin/express + +0.13.0 / 2010-06-01 +================== + + * Added node v0.1.97 compatibility + * Added support for deleting cookies via Request#cookie('key', null) + * Updated haml submodule + * Fixed not-found page, now using using charset utf-8 + * Fixed show-exceptions page, now using using charset utf-8 + * Fixed view support due to fs.readFile Buffers + * Changed; mime.type() no longer accepts ".type" due to node extname() changes + +0.12.0 / 2010-05-22 +================== + + * Added node v0.1.96 compatibility + * Added view `helpers` export which act as additional local variables + * Updated haml submodule + * Changed ETag; removed inode, modified time only + * Fixed LF to CRLF for setting multiple cookies + * Fixed cookie complation; values are now urlencoded + * Fixed cookies parsing; accepts quoted values and url escaped cookies + +0.11.0 / 2010-05-06 +================== + + * Added support for layouts using different engines + - this.render('page.html.haml', { layout: 'super-cool-layout.html.ejs' }) + - this.render('page.html.haml', { layout: 'foo' }) // assumes 'foo.html.haml' + - this.render('page.html.haml', { layout: false }) // no layout + * Updated ext submodule + * Updated haml submodule + * Fixed EJS partial support by passing along the context. Issue #307 + +0.10.1 / 2010-05-03 +================== + + * Fixed binary uploads. + +0.10.0 / 2010-04-30 +================== + + * Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s + encoding is set to 'utf8' or 'utf-8'. + * Added "encoding" option to Request#render(). Closes #299 + * Added "dump exceptions" setting, which is enabled by default. + * Added simple ejs template engine support + * Added error reponse support for text/plain, application/json. Closes #297 + * Added callback function param to Request#error() + * Added Request#sendHead() + * Added Request#stream() + * Added support for Request#respond(304, null) for empty response bodies + * Added ETag support to Request#sendfile() + * Added options to Request#sendfile(), passed to fs.createReadStream() + * Added filename arg to Request#download() + * Performance enhanced due to pre-reversing plugins so that plugins.reverse() is not called on each request + * Performance enhanced by preventing several calls to toLowerCase() in Router#match() + * Changed; Request#sendfile() now streams + * Changed; Renamed Request#halt() to Request#respond(). Closes #289 + * Changed; Using sys.inspect() instead of JSON.encode() for error output + * Changed; run() returns the http.Server instance. Closes #298 + * Changed; Defaulting Server#host to null (INADDR_ANY) + * Changed; Logger "common" format scale of 0.4f + * Removed Logger "request" format + * Fixed; Catching ENOENT in view caching, preventing error when "views/partials" is not found + * Fixed several issues with http client + * Fixed Logger Content-Length output + * Fixed bug preventing Opera from retaining the generated session id. Closes #292 + +0.9.0 / 2010-04-14 +================== + + * Added DSL level error() route support + * Added DSL level notFound() route support + * Added Request#error() + * Added Request#notFound() + * Added Request#render() callback function. Closes #258 + * Added "max upload size" setting + * Added "magic" variables to collection partials (\_\_index\_\_, \_\_length\_\_, \_\_isFirst\_\_, \_\_isLast\_\_). Closes #254 + * Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js + * Added callback function support to Request#halt() as 3rd/4th arg + * Added preprocessing of route param wildcards using param(). Closes #251 + * Added view partial support (with collections etc) + * Fixed bug preventing falsey params (such as ?page=0). Closes #286 + * Fixed setting of multiple cookies. Closes #199 + * Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml) + * Changed; session cookie is now httpOnly + * Changed; Request is no longer global + * Changed; Event is no longer global + * Changed; "sys" module is no longer global + * Changed; moved Request#download to Static plugin where it belongs + * Changed; Request instance created before body parsing. Closes #262 + * Changed; Pre-caching views in memory when "cache view contents" is enabled. Closes #253 + * Changed; Pre-caching view partials in memory when "cache view partials" is enabled + * Updated support to node --version 0.1.90 + * Updated dependencies + * Removed set("session cookie") in favour of use(Session, { cookie: { ... }}) + * Removed utils.mixin(); use Object#mergeDeep() + +0.8.0 / 2010-03-19 +================== + + * Added coffeescript example app. Closes #242 + * Changed; cache api now async friendly. Closes #240 + * Removed deprecated 'express/static' support. Use 'express/plugins/static' + +0.7.6 / 2010-03-19 +================== + + * Added Request#isXHR. Closes #229 + * Added `make install` (for the executable) + * Added `express` executable for setting up simple app templates + * Added "GET /public/*" to Static plugin, defaulting to /public + * Added Static plugin + * Fixed; Request#render() only calls cache.get() once + * Fixed; Namespacing View caches with "view:" + * Fixed; Namespacing Static caches with "static:" + * Fixed; Both example apps now use the Static plugin + * Fixed set("views"). Closes #239 + * Fixed missing space for combined log format + * Deprecated Request#sendfile() and 'express/static' + * Removed Server#running + +0.7.5 / 2010-03-16 +================== + + * Added Request#flash() support without args, now returns all flashes + * Updated ext submodule + +0.7.4 / 2010-03-16 +================== + + * Fixed session reaper + * Changed; class.js replacing js-oo Class implementation (quite a bit faster, no browser cruft) + +0.7.3 / 2010-03-16 +================== + + * Added package.json + * Fixed requiring of haml / sass due to kiwi removal + +0.7.2 / 2010-03-16 +================== + + * Fixed GIT submodules (HAH!) + +0.7.1 / 2010-03-16 +================== + + * Changed; Express now using submodules again until a PM is adopted + * Changed; chat example using millisecond conversions from ext + +0.7.0 / 2010-03-15 +================== + + * Added Request#pass() support (finds the next matching route, or the given path) + * Added Logger plugin (default "common" format replaces CommonLogger) + * Removed Profiler plugin + * Removed CommonLogger plugin + +0.6.0 / 2010-03-11 +================== + + * Added seed.yml for kiwi package management support + * Added HTTP client query string support when method is GET. Closes #205 + + * Added support for arbitrary view engines. + For example "foo.engine.html" will now require('engine'), + the exports from this module are cached after the first require(). + + * Added async plugin support + + * Removed usage of RESTful route funcs as http client + get() etc, use http.get() and friends + + * Removed custom exceptions + +0.5.0 / 2010-03-10 +================== + + * Added ext dependency (library of js extensions) + * Removed extname() / basename() utils. Use path module + * Removed toArray() util. Use arguments.values + * Removed escapeRegexp() util. Use RegExp.escape() + * Removed process.mixin() dependency. Use utils.mixin() + * Removed Collection + * Removed ElementCollection + * Shameless self promotion of ebook "Advanced JavaScript" (http://dev-mag.com) ;) + +0.4.0 / 2010-02-11 +================== + + * Added flash() example to sample upload app + * Added high level restful http client module (express/http) + * Changed; RESTful route functions double as HTTP clients. Closes #69 + * Changed; throwing error when routes are added at runtime + * Changed; defaulting render() context to the current Request. Closes #197 + * Updated haml submodule + +0.3.0 / 2010-02-11 +================== + + * Updated haml / sass submodules. Closes #200 + * Added flash message support. Closes #64 + * Added accepts() now allows multiple args. fixes #117 + * Added support for plugins to halt. Closes #189 + * Added alternate layout support. Closes #119 + * Removed Route#run(). Closes #188 + * Fixed broken specs due to use(Cookie) missing + +0.2.1 / 2010-02-05 +================== + + * Added "plot" format option for Profiler (for gnuplot processing) + * Added request number to Profiler plugin + * Fixed binary encoding for multi-part file uploads, was previously defaulting to UTF8 + * Fixed issue with routes not firing when not files are present. Closes #184 + * Fixed process.Promise -> events.Promise + +0.2.0 / 2010-02-03 +================== + + * Added parseParam() support for name[] etc. (allows for file inputs with "multiple" attr) Closes #180 + * Added Both Cache and Session option "reapInterval" may be "reapEvery". Closes #174 + * Added expiration support to cache api with reaper. Closes #133 + * Added cache Store.Memory#reap() + * Added Cache; cache api now uses first class Cache instances + * Added abstract session Store. Closes #172 + * Changed; cache Memory.Store#get() utilizing Collection + * Renamed MemoryStore -> Store.Memory + * Fixed use() of the same plugin several time will always use latest options. Closes #176 + +0.1.0 / 2010-02-03 +================== + + * Changed; Hooks (before / after) pass request as arg as well as evaluated in their context + * Updated node support to 0.1.27 Closes #169 + * Updated dirname(__filename) -> __dirname + * Updated libxmljs support to v0.2.0 + * Added session support with memory store / reaping + * Added quick uid() helper + * Added multi-part upload support + * Added Sass.js support / submodule + * Added production env caching view contents and static files + * Added static file caching. Closes #136 + * Added cache plugin with memory stores + * Added support to StaticFile so that it works with non-textual files. + * Removed dirname() helper + * Removed several globals (now their modules must be required) + +0.0.2 / 2010-01-10 +================== + + * Added view benchmarks; currently haml vs ejs + * Added Request#attachment() specs. Closes #116 + * Added use of node's parseQuery() util. Closes #123 + * Added `make init` for submodules + * Updated Haml + * Updated sample chat app to show messages on load + * Updated libxmljs parseString -> parseHtmlString + * Fixed `make init` to work with older versions of git + * Fixed specs can now run independant specs for those who cant build deps. Closes #127 + * Fixed issues introduced by the node url module changes. Closes 126. + * Fixed two assertions failing due to Collection#keys() returning strings + * Fixed faulty Collection#toArray() spec due to keys() returning strings + * Fixed `make test` now builds libxmljs.node before testing + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/NodeDrawing/node_modules/express/LICENSE b/NodeDrawing/node_modules/express/LICENSE new file mode 100644 index 0000000..36075a3 --- /dev/null +++ b/NodeDrawing/node_modules/express/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2009-2011 TJ Holowaychuk + +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/NodeDrawing/node_modules/express/Makefile b/NodeDrawing/node_modules/express/Makefile new file mode 100644 index 0000000..e4f9d75 --- /dev/null +++ b/NodeDrawing/node_modules/express/Makefile @@ -0,0 +1,35 @@ + +DOCS = $(shell find docs/*.md) +HTMLDOCS =$(DOCS:.md=.html) +TESTS = $(shell find test/*.test.js) + +test: + @NODE_ENV=test ./node_modules/.bin/expresso \ + -I lib \ + $(TESTFLAGS) \ + $(TESTS) + +test-cov: + @TESTFLAGS=--cov $(MAKE) test + +docs: $(HTMLDOCS) + @ echo "... generating TOC" + @./support/toc.js docs/guide.html + +%.html: %.md + @echo "... $< -> $@" + @markdown $< \ + | cat docs/layout/head.html - docs/layout/foot.html \ + > $@ + +site: + rm -fr /tmp/docs \ + && cp -fr docs /tmp/docs \ + && git checkout gh-pages \ + && cp -fr /tmp/docs/* . \ + && echo "done" + +docclean: + rm -f docs/*.{1,html} + +.PHONY: site test test-cov docs docclean \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/Readme.md b/NodeDrawing/node_modules/express/Readme.md new file mode 100644 index 0000000..23b5690 --- /dev/null +++ b/NodeDrawing/node_modules/express/Readme.md @@ -0,0 +1,143 @@ + +# Express + + Insanely fast (and small) server-side JavaScript web development framework + built on [node](http://nodejs.org) and [Connect](http://github.com/senchalabs/connect). + + var app = express.createServer(); + + app.get('/', function(req, res){ + res.send('Hello World'); + }); + + app.listen(3000); + +## Installation + + $ npm install express + +or to access the `express(1)` executable install globally: + + $ npm install -g express + +## Quick Start + + The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below: + + Create the app: + + $ npm install -g express + $ express /tmp/foo && cd /tmp/foo + + Install dependencies: + + $ npm install -d + + Start the server: + + $ node app.js + +## Features + + * Robust routing + * Redirection helpers + * Dynamic view helpers + * Content negotiation + * Focus on high performance + * View rendering and partials support + * Environment based configuration + * Session based flash notifications + * Built on [Connect](http://github.com/senchalabs/connect) + * High test coverage + * Executable for generating applications quickly + * Application level view options + +Via Connect: + + * Session support + * Cache API + * Mime helpers + * ETag support + * Persistent flash notifications + * Cookie support + * JSON-RPC + * Logging + * and _much_ more! + +## Contributors + +The following are the major contributors of Express (in no specific order). + + * TJ Holowaychuk ([visionmedia](http://github.com/visionmedia)) + * Ciaran Jessup ([ciaranj](http://github.com/ciaranj)) + * Aaron Heckmann ([aheckmann](http://github.com/aheckmann)) + * Guillermo Rauch ([guille](http://github.com/guille)) + +## More Information + + * #express on freenode + * [express-expose](http://github.com/visionmedia/express-expose) expose objects, functions, modules and more to client-side js with ease + * [express-configure](http://github.com/visionmedia/express-configuration) async configuration support + * [express-messages](http://github.com/visionmedia/express-messages) flash notification rendering helper + * [express-namespace](http://github.com/visionmedia/express-namespace) namespaced route support + * [express-params](https://github.com/visionmedia/express-params) param pre-condition functions + * [express-mongoose](https://github.com/LearnBoost/express-mongoose) plugin for easy rendering of Mongoose async Query results + * Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates + * [Google Group](http://groups.google.com/group/express-js) for discussion + * Visit the [Wiki](http://github.com/visionmedia/express/wiki) + * [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito) + * Screencast - [Introduction](http://bit.ly/eRYu0O) + * Screencast - [View Partials](http://bit.ly/dU13Fx) + * Screencast - [Route Specific Middleware](http://bit.ly/hX4IaH) + * Screencast - [Route Path Placeholder Preconditions](http://bit.ly/eNqmVs) + +## Node Compatibility + +Express 1.x is compatible with node 0.2.x and connect < 1.0. + +Express 2.x is compatible with node 0.4.x and connect 1.x + +## Viewing Examples + +First install the dev dependencies to install all the example / test suite deps: + + $ npm install + +then run whichever tests you want: + + $ node examples/jade/app.js + +## Running Tests + +To run the test suite first invoke the following command within the repo, installing the development dependencies: + + $ npm install + +then run the tests: + + $ make test + +## License + +(The MIT License) + +Copyright (c) 2009-2011 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. diff --git a/NodeDrawing/node_modules/express/bin/express b/NodeDrawing/node_modules/express/bin/express new file mode 100755 index 0000000..75071f8 --- /dev/null +++ b/NodeDrawing/node_modules/express/bin/express @@ -0,0 +1,419 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var fs = require('fs') + , exec = require('child_process').exec; + +/** + * Framework version. + */ + +var version = '2.3.12'; + +/** + * Add session support. + */ + +var sessions = false; + +/** + * CSS engine to utilize. + */ + +var cssEngine; + +/** + * Template engine to utilize. + */ + +var templateEngine = 'jade'; + +/** + * Usage documentation. + */ + +var usage = '' + + '\n' + + ' Usage: express [options] [path]\n' + + '\n' + + ' Options:\n' + + ' -s, --sessions add session support\n' + + ' -t, --template add template support (jade|ejs). default=jade\n' + + ' -c, --css add stylesheet support (less|sass|stylus). default=plain css\n' + + ' -v, --version output framework version\n' + + ' -h, --help output help information\n' + ; + +/** + * Jade layout template. + */ + +var jadeLayout = [ + '!!!' + , 'html' + , ' head' + , ' title= title' + , ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')' + , ' body!= body' +].join('\n'); + +/** + * Jade index template. + */ + +var jadeIndex = [ + 'h1= title' + , 'p Welcome to #{title}' +].join('\n'); + +/** + * EJS layout template. + */ + +var ejsLayout = [ + '' + , '' + , ' ' + , ' <%= title %>' + , ' ' + , ' ' + , ' ' + , ' <%- body %>' + , ' ' + , '' +].join('\n'); + +/** + * EJS index template. + */ + +var ejsIndex = [ + '

<%= title %>

' + , '

Welcome to <%= title %>

' + ].join('\n'); + +/** + * Default css template. + */ + +var css = [ + 'body {' + , ' padding: 50px;' + , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;' + , '}' + , '' + , 'a {' + , ' color: #00B7FF;' + , '}' +].join('\n'); + +/** + * Default less template. + */ + +var less = [ + 'body {' + , ' padding: 50px;' + , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;' + , '}' + , '' + , 'a {' + , ' color: #00B7FF;' + , '}' +].join('\n'); + +/** + * Default sass template. + */ + +var sass = [ + 'body' + , ' :padding 50px' + , ' :font 14px "Lucida Grande", Helvetica, Arial, sans-serif' + , 'a' + , ' :color #00B7FF' +].join('\n'); + +/** + * Default stylus template. + */ + +var stylus = [ + 'body' + , ' padding 50px' + , ' font 14px "Lucida Grande", Helvetica, Arial, sans-serif' + , 'a' + , ' color #00B7FF' +].join('\n'); + +/** + * App template. + */ + +var app = [ + '' + , '/**' + , ' * Module dependencies.' + , ' */' + , '' + , 'var express = require(\'express\');' + , '' + , 'var app = module.exports = express.createServer();' + , '' + , '// Configuration' + , '' + , 'app.configure(function(){' + , ' app.set(\'views\', __dirname + \'/views\');' + , ' app.set(\'view engine\', \':TEMPLATE\');' + , ' app.use(express.bodyParser());' + , ' app.use(express.methodOverride());{sess}{css}' + , ' app.use(app.router);' + , ' app.use(express.static(__dirname + \'/public\'));' + , '});' + , '' + , 'app.configure(\'development\', function(){' + , ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); ' + , '});' + , '' + , 'app.configure(\'production\', function(){' + , ' app.use(express.errorHandler()); ' + , '});' + , '' + , '// Routes' + , '' + , 'app.get(\'/\', function(req, res){' + , ' res.render(\'index\', {' + , ' title: \'Express\'' + , ' });' + , '});' + , '' + , 'app.listen(3000);' + , 'console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);' + , '' +].join('\n'); + +// Parse arguments + +var args = process.argv.slice(2) + , path = '.'; + +while (args.length) { + var arg = args.shift(); + switch (arg) { + case '-h': + case '--help': + abort(usage); + break; + case '-v': + case '--version': + abort(version); + break; + case '-s': + case '--session': + case '--sessions': + sessions = true; + break; + case '-c': + case '--css': + args.length + ? (cssEngine = args.shift()) + : abort('--css requires an argument'); + break; + case '-t': + case '--template': + args.length + ? (templateEngine = args.shift()) + : abort('--template requires an argument'); + break; + default: + path = arg; + } +} + +// Generate application + +(function createApplication(path) { + emptyDirectory(path, function(empty){ + if (empty) { + createApplicationAt(path); + } else { + confirm('destination is not empty, continue? ', function(ok){ + if (ok) { + process.stdin.destroy(); + createApplicationAt(path); + } else { + abort('aborting'); + } + }); + } + }); +})(path); + +/** + * Create application at the given directory `path`. + * + * @param {String} path + */ + +function createApplicationAt(path) { + mkdir(path, function(){ + mkdir(path + '/pids'); + mkdir(path + '/logs'); + mkdir(path + '/public/javascripts'); + mkdir(path + '/public/images'); + mkdir(path + '/public/stylesheets', function(){ + switch (cssEngine) { + case 'stylus': + write(path + '/public/stylesheets/style.styl', stylus); + break; + case 'less': + write(path + '/public/stylesheets/style.less', less); + break; + case 'sass': + write(path + '/public/stylesheets/style.sass', sass); + break; + default: + write(path + '/public/stylesheets/style.css', css); + } + }); + mkdir(path + '/views', function(){ + switch (templateEngine) { + case 'ejs': + write(path + '/views/layout.ejs', ejsLayout); + write(path + '/views/index.ejs', ejsIndex); + break; + case 'jade': + write(path + '/views/layout.jade', jadeLayout); + write(path + '/views/index.jade', jadeIndex); + break; + } + }); + + // CSS Engine support + switch (cssEngine) { + case 'sass': + case 'less': + app = app.replace('{css}', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));'); + break; + case 'stylus': + app = app.replace('{css}', '\n app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));'); + break; + default: + app = app.replace('{css}', ''); + } + + // Session support + app = app.replace('{sess}', sessions + ? '\n app.use(express.cookieParser());\n app.use(express.session({ secret: \'your secret here\' }));' + : ''); + + // Template support + app = app.replace(':TEMPLATE', templateEngine); + + // package.json + var json = '{\n'; + json += ' "name": "application-name"\n'; + json += ' , "version": "0.0.1"\n'; + json += ' , "private": true\n'; + json += ' , "dependencies": {\n'; + json += ' "express": "' + version + '"\n'; + if (cssEngine) json += ' , "' + cssEngine + '": ">= 0.0.1"\n'; + if (templateEngine) json += ' , "' + templateEngine + '": ">= 0.0.1"\n'; + json += ' }\n'; + json += '}'; + + + write(path + '/package.json', json); + write(path + '/app.js', app); + }); +} + +/** + * Check if the given directory `path` is empty. + * + * @param {String} path + * @param {Function} fn + */ + +function emptyDirectory(path, fn) { + fs.readdir(path, function(err, files){ + if (err && 'ENOENT' != err.code) throw err; + fn(!files || !files.length); + }); +} + +/** + * echo str > path. + * + * @param {String} path + * @param {String} str + */ + +function write(path, str) { + fs.writeFile(path, str); + console.log(' \x1b[36mcreate\x1b[0m : ' + path); +} + +/** + * Prompt confirmation with the given `msg`. + * + * @param {String} msg + * @param {Function} fn + */ + +function confirm(msg, fn) { + prompt(msg, function(val){ + fn(/^ *y(es)?/i.test(val)); + }); +} + +/** + * Prompt input with the given `msg` and callback `fn`. + * + * @param {String} msg + * @param {Function} fn + */ + +function prompt(msg, fn) { + // prompt + if (' ' == msg[msg.length - 1]) { + process.stdout.write(msg); + } else { + console.log(msg); + } + + // stdin + process.stdin.setEncoding('ascii'); + process.stdin.once('data', function(data){ + fn(data); + }).resume(); +} + +/** + * Mkdir -p. + * + * @param {String} path + * @param {Function} fn + */ + +function mkdir(path, fn) { + exec('mkdir -p ' + path, function(err){ + if (err) throw err; + console.log(' \x1b[36mcreate\x1b[0m : ' + path); + fn && fn(); + }); +} + +/** + * Exit with the given `str`. + * + * @param {String} str + */ + +function abort(str) { + console.error(str); + process.exit(1); +} diff --git a/NodeDrawing/node_modules/express/index.js b/NodeDrawing/node_modules/express/index.js new file mode 100644 index 0000000..8d81ea7 --- /dev/null +++ b/NodeDrawing/node_modules/express/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/express'); \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/lib/express.js b/NodeDrawing/node_modules/express/lib/express.js new file mode 100644 index 0000000..318b154 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/express.js @@ -0,0 +1,79 @@ + +/*! + * Express + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var connect = require('connect') + , HTTPSServer = require('./https') + , HTTPServer = require('./http') + , Route = require('./router/route') + +/** + * Re-export connect auto-loaders. + * + * This prevents the need to `require('connect')` in order + * to access core middleware, so for example `express.logger()` instead + * of `require('connect').logger()`. + */ + +var exports = module.exports = connect.middleware; + +/** + * Framework version. + */ + +exports.version = '2.3.12'; + +/** + * Shortcut for `new Server(...)`. + * + * @param {Function} ... + * @return {Server} + * @api public + */ + +exports.createServer = function(options){ + if ('object' == typeof options) { + return new HTTPSServer(options, Array.prototype.slice.call(arguments, 1)); + } else { + return new HTTPServer(Array.prototype.slice.call(arguments)); + } +}; + +/** + * Expose constructors. + */ + +exports.HTTPServer = HTTPServer; +exports.HTTPSServer = HTTPSServer; +exports.Route = Route; + +/** + * View extensions. + */ + +exports.View = +exports.view = require('./view'); + +/** + * Response extensions. + */ + +require('./response'); + +/** + * Request extensions. + */ + +require('./request'); + +// Error handler title + +exports.errorHandler.title = 'Express'; + diff --git a/NodeDrawing/node_modules/express/lib/http.js b/NodeDrawing/node_modules/express/lib/http.js new file mode 100644 index 0000000..22640aa --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/http.js @@ -0,0 +1,524 @@ + +/*! + * Express - HTTPServer + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var qs = require('qs') + , connect = require('connect') + , router = require('./router') + , Router = require('./router') + , view = require('./view') + , toArray = require('./utils').toArray + , methods = router.methods.concat('del', 'all') + , url = require('url') + , utils = connect.utils; + +/** + * Expose `HTTPServer`. + */ + +exports = module.exports = HTTPServer; + +/** + * Server proto. + */ + +var app = HTTPServer.prototype; + +/** + * Initialize a new `HTTPServer` with optional `middleware`. + * + * @param {Array} middleware + * @api public + */ + +function HTTPServer(middleware){ + connect.HTTPServer.call(this, []); + this.init(middleware); +}; + +/** + * Inherit from `connect.HTTPServer`. + */ + +app.__proto__ = connect.HTTPServer.prototype; + +/** + * Initialize the server. + * + * @param {Array} middleware + * @api private + */ + +app.init = function(middleware){ + var self = this; + this.cache = {}; + this.settings = {}; + this.redirects = {}; + this.isCallbacks = {}; + this._locals = {}; + this.dynamicViewHelpers = {}; + this.errorHandlers = []; + + this.set('home', '/'); + this.set('env', process.env.NODE_ENV || 'development'); + + // expose objects to each other + this.use(function(req, res, next){ + req.query = req.query || {}; + res.setHeader('X-Powered-By', 'Express'); + req.app = res.app = self; + req.res = res; + res.req = req; + req.next = next; + // assign req.query + if (req.url.indexOf('?') > 0) { + var query = url.parse(req.url).query; + req.query = qs.parse(query); + } + next(); + }); + + // apply middleware + if (middleware) middleware.forEach(self.use.bind(self)); + + // router + this.routes = new Router(this); + this.__defineGetter__('router', function(){ + this.__usedRouter = true; + return self.routes.middleware; + }); + + // default locals + this.locals({ + settings: this.settings + , app: this + }); + + // default development configuration + this.configure('development', function(){ + this.enable('hints'); + }); + + // default production configuration + this.configure('production', function(){ + this.enable('view cache'); + }); + + // register error handlers on "listening" + // so that they disregard definition position. + this.on('listening', this.registerErrorHandlers.bind(this)); + + // route manipulation methods + methods.forEach(function(method){ + self.lookup[method] = function(path){ + return self.routes.lookup(method, path); + }; + + self.match[method] = function(path){ + return self.routes.match(method, path); + }; + + self.remove[method] = function(path){ + return self.routes.lookup(method, path).remove(); + }; + }); + + // del -> delete + self.lookup.del = self.lookup.delete; + self.match.del = self.match.delete; + self.remove.del = self.remove.delete; +}; + +/** + * Remove routes matching the given `path`. + * + * @param {Route} path + * @return {Boolean} + * @api public + */ + +app.remove = function(path){ + return this.routes.lookup('all', path).remove(); +}; + +/** + * Lookup routes defined with a path + * equivalent to `path`. + * + * @param {Stirng} path + * @return {Array} + * @api public + */ + +app.lookup = function(path){ + return this.routes.lookup('all', path); +}; + +/** + * Lookup routes matching the given `url`. + * + * @param {Stirng} url + * @return {Array} + * @api public + */ + +app.match = function(url){ + return this.routes.match('all', url); +}; + +/** + * When using the vhost() middleware register error handlers. + */ + +app.onvhost = function(){ + this.registerErrorHandlers(); +}; + +/** + * Register error handlers. + * + * @return {Server} for chaining + * @api public + */ + +app.registerErrorHandlers = function(){ + this.errorHandlers.forEach(function(fn){ + this.use(function(err, req, res, next){ + fn.apply(this, arguments); + }); + }, this); + return this; +}; + +/** + * Proxy `connect.HTTPServer#use()` to apply settings to + * mounted applications. + * + * @param {String|Function|Server} route + * @param {Function|Server} middleware + * @return {Server} for chaining + * @api public + */ + +app.use = function(route, middleware){ + var app, home, handle; + + if ('string' != typeof route) { + middleware = route, route = '/'; + } + + // express app + if (middleware.handle && middleware.set) app = middleware; + + // restore .app property on req and res + if (app) { + app.route = route; + middleware = function(req, res, next) { + var orig = req.app; + app.handle(req, res, function(err){ + req.app = res.app = orig; + next(err); + }); + }; + } + + connect.HTTPServer.prototype.use.call(this, route, middleware); + + // mounted an app, invoke the hook + // and adjust some settings + if (app) { + home = app.set('home'); + if ('/' == home) home = ''; + app.set('home', app.route + home); + app.parent = this; + if (app.__mounted) app.__mounted.call(app, this); + } + + return this; +}; + +/** + * Assign a callback `fn` which is called + * when this `Server` is passed to `Server#use()`. + * + * Examples: + * + * var app = express.createServer() + * , blog = express.createServer(); + * + * blog.mounted(function(parent){ + * // parent is app + * // "this" is blog + * }); + * + * app.use(blog); + * + * @param {Function} fn + * @return {Server} for chaining + * @api public + */ + +app.mounted = function(fn){ + this.__mounted = fn; + return this; +}; + +/** + * See: view.register. + * + * @return {Server} for chaining + * @api public + */ + +app.register = function(){ + view.register.apply(this, arguments); + return this; +}; + +/** + * Register the given view helpers `obj`. This method + * can be called several times to apply additional helpers. + * + * @param {Object} obj + * @return {Server} for chaining + * @api public + */ + +app.helpers = +app.locals = function(obj){ + utils.merge(this._locals, obj); + return this; +}; + +/** + * Register the given dynamic view helpers `obj`. This method + * can be called several times to apply additional helpers. + * + * @param {Object} obj + * @return {Server} for chaining + * @api public + */ + +app.dynamicHelpers = function(obj){ + utils.merge(this.dynamicViewHelpers, obj); + return this; +}; + +/** + * Map the given param placeholder `name`(s) to the given callback `fn`. + * + * Param mapping is used to provide pre-conditions to routes + * which us normalized placeholders. This callback has the same + * signature as regular middleware, for example below when ":userId" + * is used this function will be invoked in an attempt to load the user. + * + * app.param('userId', function(req, res, next, id){ + * User.find(id, function(err, user){ + * if (err) { + * next(err); + * } else if (user) { + * req.user = user; + * next(); + * } else { + * next(new Error('failed to load user')); + * } + * }); + * }); + * + * @param {String|Array|Function} name + * @param {Function} fn + * @return {Server} for chaining + * @api public + */ + +app.param = function(name, fn){ + // array + if (Array.isArray(name)) { + name.forEach(function(name){ + this.param(name, fn); + }, this); + // param logic + } else if ('function' == typeof name) { + this.routes.param(name); + // single + } else { + if (':' == name[0]) name = name.substr(1); + this.routes.param(name, fn); + } + + return this; +}; + +/** + * Assign a custom exception handler callback `fn`. + * These handlers are always _last_ in the middleware stack. + * + * @param {Function} fn + * @return {Server} for chaining + * @api public + */ + +app.error = function(fn){ + this.errorHandlers.push(fn); + return this; +}; + +/** + * Register the given callback `fn` for the given `type`. + * + * @param {String} type + * @param {Function} fn + * @return {Server} for chaining + * @api public + */ + +app.is = function(type, fn){ + if (!fn) return this.isCallbacks[type]; + this.isCallbacks[type] = fn; + return this; +}; + +/** + * Assign `setting` to `val`, or return `setting`'s value. + * Mounted servers inherit their parent server's settings. + * + * @param {String} setting + * @param {String} val + * @return {Server|Mixed} for chaining, or the setting value + * @api public + */ + +app.set = function(setting, val){ + if (val === undefined) { + if (this.settings.hasOwnProperty(setting)) { + return this.settings[setting]; + } else if (this.parent) { + return this.parent.set(setting); + } + } else { + this.settings[setting] = val; + return this; + } +}; + +/** + * Check if `setting` is enabled. + * + * @param {String} setting + * @return {Boolean} + * @api public + */ + +app.enabled = function(setting){ + return !!this.set(setting); +}; + +/** + * Check if `setting` is disabled. + * + * @param {String} setting + * @return {Boolean} + * @api public + */ + +app.disabled = function(setting){ + return !this.set(setting); +}; + +/** + * Enable `setting`. + * + * @param {String} setting + * @return {Server} for chaining + * @api public + */ + +app.enable = function(setting){ + return this.set(setting, true); +}; + +/** + * Disable `setting`. + * + * @param {String} setting + * @return {Server} for chaining + * @api public + */ + +app.disable = function(setting){ + return this.set(setting, false); +}; + +/** + * Redirect `key` to `url`. + * + * @param {String} key + * @param {String} url + * @return {Server} for chaining + * @api public + */ + +app.redirect = function(key, url){ + this.redirects[key] = url; + return this; +}; + +/** + * Configure callback for the given `env`. + * + * @param {String} env + * @param {Function} fn + * @return {Server} for chaining + * @api public + */ + +app.configure = function(env, fn){ + if ('function' == typeof env) fn = env, env = 'all'; + if ('all' == env || env == this.settings.env) fn.call(this); + return this; +}; + +/** + * Delegate `.VERB(...)` calls to `.route(VERB, ...)`. + */ + +methods.forEach(function(method){ + app[method] = function(path){ + if (1 == arguments.length) return this.routes.lookup(method, path); + var args = [method].concat(toArray(arguments)); + if (!this.__usedRouter) this.use(this.router); + return this.routes._route.apply(this.routes, args); + } +}); + +/** + * Special-cased "all" method, applying the given route `path`, + * middleware, and callback to _every_ HTTP method. + * + * @param {String} path + * @param {Function} ... + * @return {Server} for chaining + * @api public + */ + +app.all = function(path){ + var args = arguments; + if (1 == args.length) return this.routes.lookup('all', path); + methods.forEach(function(method){ + if ('all' == method) return; + app[method].apply(this, args); + }, this); + return this; +}; + +// del -> delete alias + +app.del = app.delete; + diff --git a/NodeDrawing/node_modules/express/lib/https.js b/NodeDrawing/node_modules/express/lib/https.js new file mode 100644 index 0000000..8a8c008 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/https.js @@ -0,0 +1,52 @@ + +/*! + * Express - HTTPSServer + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var connect = require('connect') + , HTTPServer = require('./http') + , https = require('https'); + +/** + * Expose `HTTPSServer`. + */ + +exports = module.exports = HTTPSServer; + +/** + * Server proto. + */ + +var app = HTTPSServer.prototype; + +/** + * Initialize a new `HTTPSServer` with the + * given `options`, and optional `middleware`. + * + * @param {Object} options + * @param {Array} middleware + * @api public + */ + +function HTTPSServer(options, middleware){ + connect.HTTPSServer.call(this, options, []); + this.init(middleware); +}; + +/** + * Inherit from `connect.HTTPSServer`. + */ + +app.__proto__ = connect.HTTPSServer.prototype; + +// mixin HTTPServer methods + +Object.keys(HTTPServer.prototype).forEach(function(method){ + app[method] = HTTPServer.prototype[method]; +}); diff --git a/NodeDrawing/node_modules/express/lib/request.js b/NodeDrawing/node_modules/express/lib/request.js new file mode 100644 index 0000000..f9d2162 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/request.js @@ -0,0 +1,309 @@ + +/*! + * Express - request + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , req = http.IncomingMessage.prototype + , utils = require('./utils') + , mime = require('mime'); + +/** + * Default flash formatters. + * + * @type Object + */ + +var flashFormatters = exports.flashFormatters = { + s: function(val){ + return String(val); + } +}; + +/** + * Return request header or optional default. + * + * The `Referrer` header field is special-cased, + * both `Referrer` and `Referer` will yield are + * interchangeable. + * + * Examples: + * + * req.header('Content-Type'); + * // => "text/plain" + * + * req.header('content-type'); + * // => "text/plain" + * + * req.header('Accept'); + * // => undefined + * + * req.header('Accept', 'text/html'); + * // => "text/html" + * + * @param {String} name + * @param {String} defaultValue + * @return {String} + * @api public + */ + +req.header = function(name, defaultValue){ + switch (name = name.toLowerCase()) { + case 'referer': + case 'referrer': + return this.headers.referrer + || this.headers.referer + || defaultValue; + default: + return this.headers[name] || defaultValue; + } +}; + +/** + * Get `field`'s `param` value, defaulting to ''. + * + * Examples: + * + * req.get('content-disposition', 'filename'); + * // => "something.png" + * + * @param {String} field + * @param {String} param + * @return {String} + * @api public + */ + +req.get = function(field, param){ + var val = this.header(field); + if (!val) return ''; + var regexp = new RegExp(param + ' *= *(?:"([^"]+)"|([^;]+))', 'i'); + if (!regexp.exec(val)) return ''; + return RegExp.$1 || RegExp.$2; +}; + +/** + * Check if the _Accept_ header is present, and includes the given `type`. + * + * When the _Accept_ header is not present `true` is returned. Otherwise + * the given `type` is matched by an exact match, and then subtypes. You + * may pass the subtype such as "html" which is then converted internally + * to "text/html" using the mime lookup table. + * + * Examples: + * + * // Accept: text/html + * req.accepts('html'); + * // => true + * + * // Accept: text/*; application/json + * req.accepts('html'); + * req.accepts('text/html'); + * req.accepts('text/plain'); + * req.accepts('application/json'); + * // => true + * + * req.accepts('image/png'); + * req.accepts('png'); + * // => false + * + * @param {String} type + * @return {Boolean} + * @api public + */ + +req.accepts = function(type){ + var accept = this.header('Accept'); + + // normalize extensions ".json" -> "json" + if (type && '.' == type[0]) type = type.substr(1); + + // when Accept does not exist, or is '*/*' return true + if (!accept || '*/*' == accept) { + return true; + } else if (type) { + // allow "html" vs "text/html" etc + if (!~type.indexOf('/')) type = mime.lookup(type); + + // check if we have a direct match + if (~accept.indexOf(type)) return true; + + // check if we have type/* + type = type.split('/')[0] + '/*'; + return !!~accept.indexOf(type); + } else { + return false; + } +}; + +/** + * Return the value of param `name` when present or `defaultValue`. + * + * - Checks route placeholders, ex: _/user/:id_ + * - Checks query string params, ex: ?id=12 + * - Checks urlencoded body params, ex: id=12 + * + * To utilize urlencoded request bodies, `req.body` + * should be an object. This can be done by using + * the `connect.bodyParser` middleware. + * + * @param {String} name + * @param {Mixed} defaultValue + * @return {String} + * @api public + */ + +req.param = function(name, defaultValue){ + // route params like /user/:id + if (this.params && this.params.hasOwnProperty(name) && undefined !== this.params[name]) { + return this.params[name]; + } + // query string params + if (undefined !== this.query[name]) { + return this.query[name]; + } + // request body params via connect.bodyParser + if (this.body && undefined !== this.body[name]) { + return this.body[name]; + } + return defaultValue; +}; + +/** + * Queue flash `msg` of the given `type`. + * + * Examples: + * + * req.flash('info', 'email sent'); + * req.flash('error', 'email delivery failed'); + * req.flash('info', 'email re-sent'); + * // => 2 + * + * req.flash('info'); + * // => ['email sent', 'email re-sent'] + * + * req.flash('info'); + * // => [] + * + * req.flash(); + * // => { error: ['email delivery failed'], info: [] } + * + * Formatting: + * + * Flash notifications also support arbitrary formatting support. + * For example you may pass variable arguments to `req.flash()` + * and use the %s specifier to be replaced by the associated argument: + * + * req.flash('info', 'email has been sent to %s.', userName); + * + * To add custom formatters use the `exports.flashFormatters` object. + * + * @param {String} type + * @param {String} msg + * @return {Array|Object|Number} + * @api public + */ + +req.flash = function(type, msg){ + if (this.session === undefined) throw Error('req.flash() requires sessions'); + var msgs = this.session.flash = this.session.flash || {}; + if (type && msg) { + var i = 2 + , args = arguments + , formatters = this.app.flashFormatters || {}; + formatters.__proto__ = flashFormatters; + msg = utils.miniMarkdown(utils.escape(msg)); + msg = msg.replace(/%([a-zA-Z])/g, function(_, format){ + var formatter = formatters[format]; + if (formatter) return formatter(args[i++]); + }); + return (msgs[type] = msgs[type] || []).push(msg); + } else if (type) { + var arr = msgs[type]; + delete msgs[type]; + return arr || []; + } else { + this.session.flash = {}; + return msgs; + } +}; + +/** + * Check if the incoming request contains the "Content-Type" + * header field, and it contains the give mime `type`. + * + * Examples: + * + * // With Content-Type: text/html; charset=utf-8 + * req.is('html'); + * req.is('text/html'); + * // => true + * + * // When Content-Type is application/json + * req.is('json'); + * req.is('application/json'); + * // => true + * + * req.is('html'); + * // => false + * + * Ad-hoc callbacks can also be registered with Express, to perform + * assertions again the request, for example if we need an expressive + * way to check if our incoming request is an image, we can register "an image" + * callback: + * + * app.is('an image', function(req){ + * return 0 == req.headers['content-type'].indexOf('image'); + * }); + * + * Now within our route callbacks, we can use to to assert content types + * such as "image/jpeg", "image/png", etc. + * + * app.post('/image/upload', function(req, res, next){ + * if (req.is('an image')) { + * // do something + * } else { + * next(); + * } + * }); + * + * @param {String} type + * @return {Boolean} + * @api public + */ + +req.is = function(type){ + var fn = this.app.is(type); + if (fn) return fn(this); + var contentType = this.headers['content-type']; + if (!contentType) return; + if (!~type.indexOf('/')) type = mime.lookup(type); + if (~type.indexOf('*')) { + type = type.split('/') + contentType = contentType.split('/'); + if ('*' == type[0] && type[1] == contentType[1]) return true; + if ('*' == type[1] && type[0] == contentType[0]) return true; + } + return !! ~contentType.indexOf(type); +}; + +// Callback for isXMLHttpRequest / xhr + +function isxhr() { + return this.header('X-Requested-With', '').toLowerCase() === 'xmlhttprequest'; +} + +/** + * Check if the request was an _XMLHttpRequest_. + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('isXMLHttpRequest', isxhr); +req.__defineGetter__('xhr', isxhr); diff --git a/NodeDrawing/node_modules/express/lib/response.js b/NodeDrawing/node_modules/express/lib/response.js new file mode 100644 index 0000000..f0e53f9 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/response.js @@ -0,0 +1,422 @@ + +/*! + * Express - response + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , http = require('http') + , path = require('path') + , connect = require('connect') + , utils = connect.utils + , parseRange = require('./utils').parseRange + , res = http.ServerResponse.prototype + , send = connect.static.send + , mime = require('mime') + , basename = path.basename + , join = path.join; + +/** + * Send a response with the given `body` and optional `headers` and `status` code. + * + * Examples: + * + * res.send(); + * res.send(new Buffer('wahoo')); + * res.send({ some: 'json' }); + * res.send('

some html

'); + * res.send('Sorry, cant find that', 404); + * res.send('text', { 'Content-Type': 'text/plain' }, 201); + * res.send(404); + * + * @param {String|Object|Number|Buffer} body or status + * @param {Object|Number} headers or status + * @param {Number} status + * @return {ServerResponse} + * @api public + */ + +res.send = function(body, headers, status){ + // allow status as second arg + if ('number' == typeof headers) { + status = headers, + headers = null; + } + + // default status + status = status || this.statusCode; + + // allow 0 args as 204 + if (!arguments.length || undefined === body) body = status = 204; + + // determine content type + switch (typeof body) { + case 'number': + if (!this.header('Content-Type')) { + this.contentType('.txt'); + } + body = http.STATUS_CODES[status = body]; + break; + case 'string': + if (!this.header('Content-Type')) { + this.charset = this.charset || 'utf-8'; + this.contentType('.html'); + } + break; + case 'boolean': + case 'object': + if (Buffer.isBuffer(body)) { + if (!this.header('Content-Type')) { + this.contentType('.bin'); + } + } else { + if (!this.header('Content-Type')) { + this.charset = this.charset || 'utf-8'; + this.contentType('.json'); + } + body = JSON.stringify(body); + if (this.req.query.callback && this.app.set('jsonp callback')) { + this.charset = this.charset || 'utf-8'; + this.header('Content-Type', 'text/javascript'); + body = this.req.query.callback.replace(/[^\w$.]/g, '') + '(' + body + ');'; + } + } + break; + } + + // populate Content-Length + if (!this.header('Content-Length')) { + this.header('Content-Length', Buffer.isBuffer(body) + ? body.length + : Buffer.byteLength(body)); + } + + // merge headers passed + if (headers) { + var fields = Object.keys(headers); + for (var i = 0, len = fields.length; i < len; ++i) { + var field = fields[i]; + this.header(field, headers[field]); + } + } + + // strip irrelevant headers + if (204 == status || 304 == status) { + this.removeHeader('Content-Type'); + this.removeHeader('Content-Length'); + } + + // respond + this.statusCode = status; + this.end('HEAD' == this.req.method ? undefined : body); +}; + +/** + * Transfer the file at the given `path`. Automatically sets + * the _Content-Type_ response header field. `next()` is called + * when `path` is a directory, or when an error occurs. + * + * Options: + * + * - `maxAge` defaulting to 0 + * - `root` root directory for relative filenames + * + * @param {String} path + * @param {Object|Function} options or fn + * @param {Function} fn + * @api public + */ + +res.sendfile = function(path, options, fn){ + var next = this.req.next; + options = options || {}; + + // support function as second arg + if ('function' == typeof options) { + fn = options; + options = {}; + } + + options.path = encodeURIComponent(path); + options.callback = fn; + send(this.req, this, next, options); +}; + +/** + * Set _Content-Type_ response header passed through `mime.lookup()`. + * + * Examples: + * + * var filename = 'path/to/image.png'; + * res.contentType(filename); + * // res.headers['Content-Type'] is now "image/png" + * + * res.contentType('.html'); + * res.contentType('html'); + * res.contentType('json'); + * res.contentType('png'); + * + * @param {String} type + * @return {String} the resolved mime type + * @api public + */ + +res.contentType = function(type){ + return this.header('Content-Type', mime.lookup(type)); +}; + +/** + * Set _Content-Disposition_ header to _attachment_ with optional `filename`. + * + * @param {String} filename + * @return {ServerResponse} + * @api public + */ + +res.attachment = function(filename){ + if (filename) this.contentType(filename); + this.header('Content-Disposition', filename + ? 'attachment; filename="' + basename(filename) + '"' + : 'attachment'); + return this; +}; + +/** + * Transfer the file at the given `path`, with optional + * `filename` as an attachment and optional callback `fn(err)`, + * and optional `fn2(err)` which is invoked when an error has + * occurred after header has been sent. + * + * @param {String} path + * @param {String|Function} filename or fn + * @param {Function} fn + * @param {Function} fn2 + * @api public + */ + +res.download = function(path, filename, fn, fn2){ + var self = this; + + // support callback as second arg + if ('function' == typeof filename) { + fn2 = fn; + fn = filename; + filename = null; + } + + // transfer the file + this.attachment(filename || path).sendfile(path, function(err){ + var sentHeader = self._header; + if (err) { + if (!sentHeader) self.removeHeader('Content-Disposition'); + if (sentHeader) { + fn2 && fn2(err); + } else if (fn) { + fn(err); + } else { + self.req.next(err); + } + } else if (fn) { + fn(); + } + }); +}; + +/** + * Set or get response header `name` with optional `val`. + * + * @param {String} name + * @param {String} val + * @return {String} + * @api public + */ + +res.header = function(name, val){ + if (val === undefined) { + return this.getHeader(name); + } else { + this.setHeader(name, val); + return val; + } +}; + +/** + * Clear cookie `name`. + * + * @param {String} name + * @param {Object} options + * @api public + */ + +res.clearCookie = function(name, options){ + var opts = { expires: new Date(1) }; + this.cookie(name, '', options + ? utils.merge(options, opts) + : opts); +}; + +/** + * Set cookie `name` to `val`, with the given `options`. + * + * Options: + * + * - `maxAge` max-age in milliseconds, converted to `expires` + * + * Examples: + * + * // "Remember Me" for 15 minutes + * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); + * + * // save as above + * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }) + * + * @param {String} name + * @param {String} val + * @param {Options} options + * @api public + */ + +res.cookie = function(name, val, options){ + options = options || {}; + if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge); + var cookie = utils.serializeCookie(name, val, options); + this.header('Set-Cookie', cookie); +}; + +/** + * Redirect to the given `url` with optional response `status` + * defauling to 302. + * + * The given `url` can also be the name of a mapped url, for + * example by default express supports "back" which redirects + * to the _Referrer_ or _Referer_ headers or the application's + * "home" setting. Express also supports "home" out of the box, + * which can be set via `app.set('home', '/blog');`, and defaults + * to '/'. + * + * Redirect Mapping: + * + * To extend the redirect mapping capabilities that Express provides, + * we may use the `app.redirect()` method: + * + * app.redirect('google', 'http://google.com'); + * + * Now in a route we may call: + * + * res.redirect('google'); + * + * We may also map dynamic redirects: + * + * app.redirect('comments', function(req, res){ + * return '/post/' + req.params.id + '/comments'; + * }); + * + * So now we may do the following, and the redirect will dynamically adjust to + * the context of the request. If we called this route with _GET /post/12_ our + * redirect _Location_ would be _/post/12/comments_. + * + * app.get('/post/:id', function(req, res){ + * res.redirect('comments'); + * }); + * + * Unless an absolute `url` is given, the app's mount-point + * will be respected. For example if we redirect to `/posts`, + * and our app is mounted at `/blog` we will redirect to `/blog/posts`. + * + * @param {String} url + * @param {Number} code + * @api public + */ + +res.redirect = function(url, status){ + var app = this.app + , req = this.req + , base = app.set('home') || '/' + , status = status || 302 + , body; + + // Setup redirect map + var map = { + back: req.header('Referrer', base) + , home: base + }; + + // Support custom redirect map + map.__proto__ = app.redirects; + + // Attempt mapped redirect + var mapped = 'function' == typeof map[url] + ? map[url](req, this) + : map[url]; + + // Perform redirect + url = mapped || url; + + // Relative + if (!~url.indexOf('://')) { + // Respect mount-point + if (app.route) url = join(app.route, url); + + // Absolute + var host = req.headers.host + , tls = req.connection.encrypted; + url = 'http' + (tls ? 's' : '') + '://' + host + url; + } + + + // Support text/{plain,html} by default + if (req.accepts('html')) { + body = '

' + http.STATUS_CODES[status] + '. Redirecting to ' + url + '

'; + this.header('Content-Type', 'text/html'); + } else { + body = http.STATUS_CODES[status] + '. Redirecting to ' + url; + this.header('Content-Type', 'text/plain'); + } + + // Respond + this.statusCode = status; + this.header('Location', url); + this.end(body); +}; + +/** + * Assign the view local variable `name` to `val` or return the + * local previously assigned to `name`. + * + * @param {String} name + * @param {Mixed} val + * @return {Mixed} val + * @api public + */ + +res.local = function(name, val){ + this._locals = this._locals || {}; + return undefined === val + ? this._locals[name] + : this._locals[name] = val; +}; + +/** + * Assign several locals with the given `obj`, + * or return the locals. + * + * @param {Object} obj + * @return {Object|Undefined} + * @api public + */ + +res.locals = +res.helpers = function(obj){ + if (obj) { + for (var key in obj) { + this.local(key, obj[key]); + } + } else { + return this._locals; + } +}; diff --git a/NodeDrawing/node_modules/express/lib/router/collection.js b/NodeDrawing/node_modules/express/lib/router/collection.js new file mode 100644 index 0000000..991a9a2 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/router/collection.js @@ -0,0 +1,53 @@ + +/*! + * Express - router - Collection + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Expose `Collection`. + */ + +module.exports = Collection; + +/** + * Initialize a new route `Collection` + * with the given `router`. + * + * @param {Router} router + * @api private + */ + +function Collection(router) { + Array.apply(this, arguments); + this.router = router; +} + +/** + * Inherit from `Array.prototype`. + */ + +Collection.prototype.__proto__ = Array.prototype; + +/** + * Remove the routes in this collection. + * + * @return {Collection} of routes removed + * @api public + */ + +Collection.prototype.remove = function(){ + var router = this.router + , len = this.length + , ret = new Collection(this.router); + + for (var i = 0; i < len; ++i) { + if (router.remove(this[i])) { + ret.push(this[i]); + } + } + + return ret; +}; + diff --git a/NodeDrawing/node_modules/express/lib/router/index.js b/NodeDrawing/node_modules/express/lib/router/index.js new file mode 100644 index 0000000..dbe7ea7 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/router/index.js @@ -0,0 +1,383 @@ + +/*! + * Express - Router + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Route = require('./route') + , Collection = require('./collection') + , utils = require('../utils') + , parse = require('url').parse + , toArray = utils.toArray; + +/** + * Expose `Router` constructor. + */ + +exports = module.exports = Router; + +/** + * Expose HTTP methods. + */ + +var methods = exports.methods = require('./methods'); + +/** + * Initialize a new `Router` with the given `app`. + * + * @param {express.HTTPServer} app + * @api private + */ + +function Router(app) { + var self = this; + this.app = app; + this.routes = {}; + this.params = {}; + this._params = []; + + this.middleware = function(req, res, next){ + self._dispatch(req, res, next); + }; +} + +/** + * Register a param callback `fn` for the given `name`. + * + * @param {String|Function} name + * @param {Function} fn + * @return {Router} for chaining + * @api public + */ + +Router.prototype.param = function(name, fn){ + // param logic + if ('function' == typeof name) { + this._params.push(name); + return; + } + + // apply param functions + var params = this._params + , len = params.length + , ret; + + for (var i = 0; i < len; ++i) { + if (ret = params[i](name, fn)) { + fn = ret; + } + } + + // ensure we end up with a + // middleware function + if ('function' != typeof fn) { + throw new Error('invalid param() call for ' + name + ', got ' + fn); + } + + this.params[name] = fn; + return this; +}; + +/** + * Remove the given `route`, returns + * a bool indicating if the route was present + * or not. + * + * @param {Route} route + * @return {Boolean} + * @api public + */ + +Router.prototype.remove = function(route){ + var routes = this.routes[route.method] + , len = routes.length; + + for (var i = 0; i < len; ++i) { + if (route == routes[i]) { + routes.splice(i, 1); + return true; + } + } +}; + +/** + * Return routes with route paths matching `path`. + * + * @param {String} method + * @param {String} path + * @return {Collection} + * @api public + */ + +Router.prototype.lookup = function(method, path){ + return this.find(function(route){ + return path == route.path + && (route.method == method + || method == 'all'); + }); +}; + +/** + * Return routes with regexps that match the given `url`. + * + * @param {String} method + * @param {String} url + * @return {Collection} + * @api public + */ + +Router.prototype.match = function(method, url){ + return this.find(function(route){ + return route.match(url) + && (route.method == method + || method == 'all'); + }); +}; + +/** + * Find routes based on the return value of `fn` + * which is invoked once per route. + * + * @param {Function} fn + * @return {Collection} + * @api public + */ + +Router.prototype.find = function(fn){ + var len = methods.length + , ret = new Collection(this) + , method + , routes + , route; + + for (var i = 0; i < len; ++i) { + method = methods[i]; + routes = this.routes[method]; + if (!routes) continue; + for (var j = 0, jlen = routes.length; j < jlen; ++j) { + route = routes[j]; + if (fn(route)) ret.push(route); + } + } + + return ret; +}; + +/** + * Route dispatcher aka the route "middleware". + * + * @param {IncomingMessage} req + * @param {ServerResponse} res + * @param {Function} next + * @api private + */ + +Router.prototype._dispatch = function(req, res, next){ + var params = this.params + , self = this; + + // route dispatch + (function pass(i){ + var route + , keys + , ret; + + // match next route + function nextRoute() { + pass(req._route_index + 1); + } + + // match route + req.route = route = self._match(req, i); + + // implied OPTIONS + if (!route && 'OPTIONS' == req.method) return self._options(req, res); + + // no route + if (!route) return next(); + + // we have a route + // start at param 0 + req.params = route.params; + keys = route.keys; + i = 0; + + (function param(err) { + var key = keys[i++] + , val = key && req.params[key.name] + , fn = key && params[key.name] + , ret; + + try { + if ('route' == err) { + nextRoute(); + } else if (err) { + next(err); + } else if (fn && undefined !== val) { + fn(req, res, param, val); + } else if (key) { + param(); + } else { + i = 0; + middleware(); + } + } catch (err) { + next(err); + } + })(); + + // invoke route middleware + function middleware(err) { + var fn = route.middleware[i++]; + if ('route' == err) { + nextRoute(); + } else if (err) { + next(err); + } else if (fn) { + fn(req, res, middleware); + } else { + done(); + } + }; + + // invoke middleware callback + function done() { + route.callback.call(self, req, res, function(err){ + if (err) return next(err); + pass(req._route_index + 1); + }); + } + })(0); +}; + +/** + * Respond to __OPTIONS__ method. + * + * @param {IncomingMessage} req + * @param {ServerResponse} res + * @api private + */ + +Router.prototype._options = function(req, res){ + var path = parse(req.url).pathname + , body = this._optionsFor(path).join(','); + res.send(body, { Allow: body }); +}; + +/** + * Return an array of HTTP verbs or "options" for `path`. + * + * @param {String} path + * @return {Array} + * @api private + */ + +Router.prototype._optionsFor = function(path){ + var self = this; + return methods.filter(function(method){ + var routes = self.routes[method]; + if (!routes || 'options' == method) return; + for (var i = 0, len = routes.length; i < len; ++i) { + if (routes[i].match(path)) return true; + } + }).map(function(method){ + return method.toUpperCase(); + }); +}; + +/** + * Attempt to match a route for `req` + * starting from offset `i`. + * + * @param {IncomingMessage} req + * @param {Number} i + * @return {Route} + * @api private + */ + +Router.prototype._match = function(req, i){ + var method = req.method.toLowerCase() + , url = parse(req.url) + , path = url.pathname + , routes = this.routes + , captures + , route + , keys; + + // pass HEAD to GET routes + if ('head' == method) method = 'get'; + + // routes for this method + if (routes = routes[method]) { + + // matching routes + for (var len = routes.length; i < len; ++i) { + route = routes[i]; + if (captures = route.match(path)) { + keys = route.keys; + route.params = []; + + // params from capture groups + for (var j = 1, jlen = captures.length; j < jlen; ++j) { + var key = keys[j-1] + , val = 'string' == typeof captures[j] + ? decodeURIComponent(captures[j]) + : captures[j]; + if (key) { + route.params[key.name] = val; + } else { + route.params.push(val); + } + } + + // all done + req._route_index = i; + return route; + } + } + } +}; + +/** + * Route `method`, `path`, and optional middleware + * to the callback `fn`. + * + * @param {String} method + * @param {String} path + * @param {Function} ... + * @param {Function} fn + * @return {Router} for chaining + * @api private + */ + +Router.prototype._route = function(method, path, fn){ + var app = this.app + , middleware = []; + + // slice middleware + if (arguments.length > 3) { + middleware = toArray(arguments, 2); + fn = middleware.pop(); + middleware = utils.flatten(middleware); + } + + // ensure path and callback are given + if (!path) throw new Error(method + 'route requires a path'); + if (!fn) throw new Error(method + ' route ' + path + ' requires a callback'); + + // create the route + var route = new Route(method, path, fn, { + sensitive: app.enabled('case sensitive routes') + , middleware: middleware + }); + + // add it + (this.routes[method] = this.routes[method] || []) + .push(route); + return this; +}; diff --git a/NodeDrawing/node_modules/express/lib/router/methods.js b/NodeDrawing/node_modules/express/lib/router/methods.js new file mode 100644 index 0000000..e19787b --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/router/methods.js @@ -0,0 +1,70 @@ + +/*! + * Express - router - methods + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Hypertext Transfer Protocol -- HTTP/1.1 + * http://www.ietf.org/rfc/rfc2616.txt + */ + +var RFC2616 = ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT']; + +/** + * HTTP Extensions for Distributed Authoring -- WEBDAV + * http://www.ietf.org/rfc/rfc2518.txt + */ + +var RFC2518 = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK']; + +/** + * Versioning Extensions to WebDAV + * http://www.ietf.org/rfc/rfc3253.txt + */ + +var RFC3253 = ['VERSION-CONTROL', 'REPORT', 'CHECKOUT', 'CHECKIN', 'UNCHECKOUT', 'MKWORKSPACE', 'UPDATE', 'LABEL', 'MERGE', 'BASELINE-CONTROL', 'MKACTIVITY']; + +/** + * Ordered Collections Protocol (WebDAV) + * http://www.ietf.org/rfc/rfc3648.txt + */ + +var RFC3648 = ['ORDERPATCH']; + +/** + * Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol + * http://www.ietf.org/rfc/rfc3744.txt + */ + +var RFC3744 = ['ACL']; + +/** + * Web Distributed Authoring and Versioning (WebDAV) SEARCH + * http://www.ietf.org/rfc/rfc5323.txt + */ + +var RFC5323 = ['SEARCH']; + +/** + * PATCH Method for HTTP + * http://www.ietf.org/rfc/rfc5789.txt + */ + +var RFC5789 = ['PATCH']; + +/** + * Expose the methods. + */ + +module.exports = [].concat( + RFC2616 + , RFC2518 + , RFC3253 + , RFC3648 + , RFC3744 + , RFC5323 + , RFC5789).map(function(method){ + return method.toLowerCase(); + }); diff --git a/NodeDrawing/node_modules/express/lib/router/route.js b/NodeDrawing/node_modules/express/lib/router/route.js new file mode 100644 index 0000000..6058d86 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/router/route.js @@ -0,0 +1,85 @@ + +/*! + * Express - router - Route + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Expose `Route`. + */ + +module.exports = Route; + +/** + * Initialize `Route` with the given HTTP `method`, `path`, + * and callback `fn` and `options`. + * + * Options: + * + * - `sensitive` enable case-sensitive routes + * - `middleware` array of middleware + * + * @param {String} method + * @param {String} path + * @param {Function} fn + * @param {Object} options. + * @api private + */ + +function Route(method, path, fn, options) { + options = options || {}; + this.callback = fn; + this.path = path; + this.method = method; + this.regexp = normalize(path, this.keys = [], options.sensitive); + this.middleware = options.middleware; +} + +/** + * Check if this route matches `path` and return captures made. + * + * @param {String} path + * @return {Array} + * @api private + */ + +Route.prototype.match = function(path){ + return this.regexp.exec(path); +}; + +/** + * Normalize the given path string, + * returning a regular expression. + * + * An empty array should be passed, + * which will contain the placeholder + * key names. For example "/user/:id" will + * then contain ["id"]. + * + * @param {String|RegExp} path + * @param {Array} keys + * @param {Boolean} sensitive + * @return {RegExp} + * @api private + */ + +function normalize(path, keys, sensitive) { + if (path instanceof RegExp) return path; + path = path + .concat('/?') + .replace(/\/\(/g, '(?:/') + .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){ + keys.push({ name: key, optional: !! optional }); + slash = slash || ''; + return '' + + (optional ? '' : slash) + + '(?:' + + (optional ? slash : '') + + (format || '') + (capture || '([^/]+?)') + ')' + + (optional || ''); + }) + .replace(/([\/.])/g, '\\$1') + .replace(/\*/g, '(.+)'); + return new RegExp('^' + path + '$', sensitive ? '' : 'i'); +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/lib/utils.js b/NodeDrawing/node_modules/express/lib/utils.js new file mode 100644 index 0000000..622d9b8 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/utils.js @@ -0,0 +1,139 @@ + +/*! + * Express - Utils + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Merge object `b` with `a` giving precedence to + * values in object `a`. + * + * @param {Object} a + * @param {Object} b + * @return {Object} a + * @api private + */ + +exports.union = function(a, b){ + if (a && b) { + var keys = Object.keys(b) + , len = keys.length + , key; + for (var i = 0; i < len; ++i) { + key = keys[i]; + if (!a.hasOwnProperty(key)) { + a[key] = b[key]; + } + } + } + return a; +}; + +/** + * Flatten the given `arr`. + * + * @param {Array} arr + * @return {Array} + * @api private + */ + +exports.flatten = function(arr, ret){ + var ret = ret || [] + , len = arr.length; + for (var i = 0; i < len; ++i) { + if (Array.isArray(arr[i])) { + exports.flatten(arr[i], ret); + } else { + ret.push(arr[i]); + } + } + return ret; +}; + +/** + * Parse mini markdown implementation. + * The following conversions are supported, + * primarily for the "flash" middleware: + * + * _foo_ or *foo* become foo + * __foo__ or **foo** become foo + * [A](B) becomes A + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.miniMarkdown = function(str){ + return String(str) + .replace(/(__|\*\*)(.*?)\1/g, '$2') + .replace(/(_|\*)(.*?)\1/g, '$2') + .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); +}; + +/** + * 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, '>'); +}; + +/** + * Parse "Range" header `str` relative to the given file `size`. + * + * @param {Number} size + * @param {String} str + * @return {Array} + * @api private + */ + +exports.parseRange = function(size, str){ + var valid = true; + var arr = str.substr(6).split(',').map(function(range){ + var range = range.split('-') + , start = parseInt(range[0], 10) + , end = parseInt(range[1], 10); + + // -500 + if (isNaN(start)) { + start = size - end; + end = size - 1; + // 500- + } else if (isNaN(end)) { + end = size - 1; + } + + // Invalid + if (isNaN(start) || isNaN(end) || start > end) valid = false; + + return { start: start, end: end }; + }); + return valid ? arr : undefined; +}; + +/** + * Fast alternative to `Array.prototype.slice.call()`. + * + * @param {Arguments} args + * @param {Number} n + * @return {Array} + * @api public + */ + +exports.toArray = function(args, i){ + var arr = [] + , len = args.length + , i = i || 0; + for (; i < len; ++i) arr.push(args[i]); + return arr; +}; diff --git a/NodeDrawing/node_modules/express/lib/view.js b/NodeDrawing/node_modules/express/lib/view.js new file mode 100644 index 0000000..978d9cf --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/view.js @@ -0,0 +1,460 @@ + +/*! + * Express - view + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var path = require('path') + , extname = path.extname + , dirname = path.dirname + , basename = path.basename + , utils = require('connect').utils + , View = require('./view/view') + , partial = require('./view/partial') + , union = require('./utils').union + , merge = utils.merge + , http = require('http') + , res = http.ServerResponse.prototype; + +/** + * Expose constructors. + */ + +exports = module.exports = View; + +/** + * Export template engine registrar. + */ + +exports.register = View.register; + +/** + * Lookup and compile `view` with cache support by supplying + * both the `cache` object and `cid` string, + * followed by `options` passed to `exports.lookup()`. + * + * @param {String} view + * @param {Object} cache + * @param {Object} cid + * @param {Object} options + * @return {View} + * @api private + */ + +exports.compile = function(view, cache, cid, options){ + if (cache && cid && cache[cid]) return cache[cid]; + + // lookup + view = exports.lookup(view, options); + + // hints + if (!view.exists) { + if (options.hint) hintAtViewPaths(view.original, options); + var err = new Error('failed to locate view "' + view.original.view + '"'); + err.view = view.original; + throw err; + } + + // compile + view.fn = view.templateEngine.compile(view.contents, options); + cache[cid] = view; + + return view; +}; + +/** + * Lookup `view`, returning an instanceof `View`. + * + * Options: + * + * - `root` root directory path + * - `defaultEngine` default template engine + * - `parentView` parent `View` object + * - `cache` cache object + * - `cacheid` optional cache id + * + * Lookup: + * + * - partial `_` + * - any `/index` + * - non-layout `..//index` + * - any `/` + * - partial `/_` + * + * @param {String} view + * @param {Object} options + * @return {View} + * @api private + */ + +exports.lookup = function(view, options){ + var orig = view = new View(view, options) + , partial = options.isPartial + , layout = options.isLayout; + + // Try _ prefix ex: ./views/_.jade + // taking precedence over the direct path + if (partial) { + view = new View(orig.prefixPath, options); + if (!view.exists) view = orig; + } + + // Try index ex: ./views/user/index.jade + if (!layout && !view.exists) view = new View(orig.indexPath, options); + + // Try ..//index ex: ../user/index.jade + // when calling partial('user') within the same dir + if (!layout && !view.exists) view = new View(orig.upIndexPath, options); + + // Try root ex: /user.jade + if (!view.exists) view = new View(orig.rootPath, options); + + // Try root _ prefix ex: /_user.jade + if (!view.exists && partial) view = new View(view.prefixPath, options); + + view.original = orig; + return view; +}; + +/** + * Partial render helper. + * + * @api private + */ + +function renderPartial(res, view, options, parentLocals, parent){ + var collection, object, locals; + + if (options) { + // collection + if (options.collection) { + collection = options.collection; + delete options.collection; + } else if ('length' in options) { + collection = options; + options = {}; + } + + // locals + if (options.locals) { + locals = options.locals; + delete options.locals; + } + + // object + if ('Object' != options.constructor.name) { + object = options; + options = {}; + } else if (undefined != options.object) { + object = options.object; + delete options.object; + } + } else { + options = {}; + } + + // Inherit locals from parent + union(options, parentLocals); + + // Merge locals + if (locals) merge(options, locals); + + // Partials dont need layouts + options.isPartial = true; + options.layout = false; + + // Deduce name from view path + var name = options.as || partial.resolveObjectName(view); + + // Render partial + function render(){ + if (object) { + if ('string' == typeof name) { + options[name] = object; + } else if (name === global) { + merge(options, object); + } else { + options.scope = object; + } + } + return res.render(view, options, null, parent, true); + } + + // Collection support + if (collection) { + var len = collection.length + , buf = '' + , keys + , key + , val; + + options.collectionLength = len; + + if ('number' == typeof len || Array.isArray(collection)) { + for (var i = 0; i < len; ++i) { + val = collection[i]; + options.firstInCollection = i == 0; + options.indexInCollection = i; + options.lastInCollection = i == len - 1; + object = val; + buf += render(); + } + } else { + keys = Object.keys(collection); + len = keys.length; + options.collectionLength = len; + options.collectionKeys = keys; + for (var i = 0; i < len; ++i) { + key = keys[i]; + val = collection[key]; + options.keyInCollection = key; + options.firstInCollection = i == 0; + options.indexInCollection = i; + options.lastInCollection = i == len - 1; + object = val; + buf += render(); + } + } + + return buf; + } else { + return render(); + } +}; + +/** + * Render `view` partial with the given `options`. Optionally a + * callback `fn(err, str)` may be passed instead of writing to + * the socket. + * + * Options: + * + * - `object` Single object with name derived from the view (unless `as` is present) + * + * - `as` Variable name for each `collection` value, defaults to the view name. + * * as: 'something' will add the `something` local variable + * * as: this will use the collection value as the template context + * * as: global will merge the collection value's properties with `locals` + * + * - `collection` Array of objects, the name is derived from the view name itself. + * For example _video.html_ will have a object _video_ available to it. + * + * @param {String} view + * @param {Object|Array|Function} options, collection, callback, or object + * @param {Function} fn + * @return {String} + * @api public + */ + +res.partial = function(view, options, fn){ + var app = this.app + , options = options || {} + , viewEngine = app.set('view engine') + , parent = {}; + + // accept callback as second argument + if ('function' == typeof options) { + fn = options; + options = {}; + } + + // root "views" option + parent.dirname = app.set('views') || process.cwd() + '/views'; + + // utilize "view engine" option + if (viewEngine) parent.engine = viewEngine; + + // render the partial + try { + var str = renderPartial(this, view, options, null, parent); + } catch (err) { + if (fn) { + fn(err); + } else { + this.req.next(err); + } + return; + } + + // callback or transfer + if (fn) { + fn(null, str); + } else { + this.send(str); + } +}; + +/** + * Render `view` with the given `options` and optional callback `fn`. + * When a callback function is given a response will _not_ be made + * automatically, however otherwise a response of _200_ and _text/html_ is given. + * + * Options: + * + * - `scope` Template evaluation context (the value of `this`) + * - `debug` Output debugging information + * - `status` Response status code + * + * @param {String} view + * @param {Object|Function} options or callback function + * @param {Function} fn + * @api public + */ + +res.render = function(view, opts, fn, parent, sub){ + // support callback function as second arg + if ('function' == typeof opts) { + fn = opts, opts = null; + } + + try { + return this._render(view, opts, fn, parent, sub); + } catch (err) { + // callback given + if (fn) { + fn(err); + // unwind to root call to prevent + // several next(err) calls + } else if (sub) { + throw err; + // root template, next(err) + } else { + this.req.next(err); + } + } +}; + +// private render() + +res._render = function(view, opts, fn, parent, sub){ + var options = {} + , self = this + , app = this.app + , helpers = app._locals + , dynamicHelpers = app.dynamicViewHelpers + , viewOptions = app.set('view options') + , root = app.set('views') || process.cwd() + '/views'; + + // cache id + var cid = app.enabled('view cache') + ? view + (parent ? ':' + parent.path : '') + : false; + + // merge "view options" + if (viewOptions) merge(options, viewOptions); + + // merge res._locals + if (this._locals) merge(options, this._locals); + + // merge render() options + if (opts) merge(options, opts); + + // merge render() .locals + if (opts && opts.locals) merge(options, opts.locals); + + // status support + if (options.status) this.statusCode = options.status; + + // capture attempts + options.attempts = []; + + var partial = options.isPartial + , layout = options.layout; + + // Layout support + if (true === layout || undefined === layout) { + layout = 'layout'; + } + + // Default execution scope to a plain object + options.scope = options.scope || {}; + + // Populate view + options.parentView = parent; + + // "views" setting + options.root = root; + + // "view engine" setting + options.defaultEngine = app.set('view engine'); + + // charset option + if (options.charset) this.charset = options.charset; + + // Dynamic helper support + if (false !== options.dynamicHelpers) { + // cache + if (!this.__dynamicHelpers) { + this.__dynamicHelpers = {}; + for (var key in dynamicHelpers) { + this.__dynamicHelpers[key] = dynamicHelpers[key].call( + this.app + , this.req + , this); + } + } + + // apply + merge(options, this.__dynamicHelpers); + } + + // Merge view helpers + union(options, helpers); + + // Always expose partial() as a local + options.partial = function(path, opts){ + return renderPartial(self, path, opts, options, view); + }; + + // View lookup + options.hint = app.enabled('hints'); + view = exports.compile(view, app.cache, cid, options); + options.filename = view.path; + + // layout helper + options.layout = function(path){ + layout = path; + }; + + // render + var str = view.fn.call(options.scope, options); + + // layout expected + if (layout) { + options.isLayout = true; + options.layout = false; + options.body = str; + this.render(layout, options, fn, view, true); + // partial return + } else if (partial) { + return str; + // render complete, and + // callback given + } else if (fn) { + fn(null, str); + // respond + } else { + this.send(str); + } +} + +/** + * Hint at view path resolution, outputting the + * paths that Express has tried. + * + * @api private + */ + +function hintAtViewPaths(view, options) { + console.error(); + console.error('failed to locate view "' + view.view + '", tried:'); + options.attempts.forEach(function(path){ + console.error(' - %s', path); + }); + console.error(); +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/lib/view/partial.js b/NodeDrawing/node_modules/express/lib/view/partial.js new file mode 100644 index 0000000..7d2f69b --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/view/partial.js @@ -0,0 +1,40 @@ + +/*! + * Express - view - Partial + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Memory cache. + */ + +var cache = {}; + +/** + * Resolve partial object name from the view path. + * + * Examples: + * + * "user.ejs" becomes "user" + * "forum thread.ejs" becomes "forumThread" + * "forum/thread/post.ejs" becomes "post" + * "blog-post.ejs" becomes "blogPost" + * + * @return {String} + * @api private + */ + +exports.resolveObjectName = function(view){ + return cache[view] || (cache[view] = view + .split('/') + .slice(-1)[0] + .split('.')[0] + .replace(/^_/, '') + .replace(/[^a-zA-Z0-9 ]+/g, ' ') + .split(/ +/).map(function(word, i){ + return i + ? word[0].toUpperCase() + word.substr(1) + : word; + }).join('')); +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/lib/view/view.js b/NodeDrawing/node_modules/express/lib/view/view.js new file mode 100644 index 0000000..6dcc448 --- /dev/null +++ b/NodeDrawing/node_modules/express/lib/view/view.js @@ -0,0 +1,209 @@ + +/*! + * Express - View + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var path = require('path') + , extname = path.extname + , dirname = path.dirname + , basename = path.basename + , fs = require('fs') + , stat = fs.statSync; + +/** + * Expose `View`. + */ + +exports = module.exports = View; + +/** + * Require cache. + */ + +var cache = {}; + +/** + * Initialize a new `View` with the given `view` path and `options`. + * + * @param {String} view + * @param {Object} options + * @api private + */ + +function View(view, options) { + options = options || {}; + this.view = view; + this.root = options.root; + this.relative = false !== options.relative; + this.defaultEngine = options.defaultEngine; + this.parent = options.parentView; + this.basename = basename(view); + this.engine = this.resolveEngine(); + this.extension = '.' + this.engine; + this.name = this.basename.replace(this.extension, ''); + this.path = this.resolvePath(); + this.dirname = dirname(this.path); + if (options.attempts) { + if (!~options.attempts.indexOf(this.path)) + options.attempts.push(this.path); + } +}; + +/** + * Check if the view path exists. + * + * @return {Boolean} + * @api public + */ + +View.prototype.__defineGetter__('exists', function(){ + try { + stat(this.path); + return true; + } catch (err) { + return false; + } +}); + +/** + * Resolve view engine. + * + * @return {String} + * @api private + */ + +View.prototype.resolveEngine = function(){ + // Explicit + if (~this.basename.indexOf('.')) return extname(this.basename).substr(1); + // Inherit from parent + if (this.parent) return this.parent.engine; + // Default + return this.defaultEngine; +}; + +/** + * Resolve view path. + * + * @return {String} + * @api private + */ + +View.prototype.resolvePath = function(){ + var path = this.view; + // Implicit engine + if (!~this.basename.indexOf('.')) path += this.extension; + // Absolute + if ('/' == path[0]) return path; + // Relative to parent + if (this.relative && this.parent) return this.parent.dirname + '/' + path; + // Relative to root + return this.root + ? this.root + '/' + path + : path; +}; + +/** + * Get view contents. This is a one-time hit, so we + * can afford to be sync. + * + * @return {String} + * @api public + */ + +View.prototype.__defineGetter__('contents', function(){ + return fs.readFileSync(this.path, 'utf8'); +}); + +/** + * Get template engine api, cache exports to reduce + * require() calls. + * + * @return {Object} + * @api public + */ + +View.prototype.__defineGetter__('templateEngine', function(){ + var ext = this.extension; + return cache[ext] || (cache[ext] = require(this.engine)); +}); + +/** + * Return root path alternative. + * + * @return {String} + * @api public + */ + +View.prototype.__defineGetter__('rootPath', function(){ + this.relative = false; + return this.resolvePath(); +}); + +/** + * Return index path alternative. + * + * @return {String} + * @api public + */ + +View.prototype.__defineGetter__('indexPath', function(){ + return this.dirname + + '/' + this.basename.replace(this.extension, '') + + '/index' + this.extension; +}); + +/** + * Return ..//index path alternative. + * + * @return {String} + * @api public + */ + +View.prototype.__defineGetter__('upIndexPath', function(){ + return this.dirname + '/../' + this.name + '/index' + this.extension; +}); + +/** + * Return _ prefix path alternative + * + * @return {String} + * @api public + */ + +View.prototype.__defineGetter__('prefixPath', function(){ + return this.dirname + '/_' + this.basename; +}); + +/** + * Register the given template engine `exports` + * as `ext`. For example we may wish to map ".html" + * files to jade: + * + * app.register('.html', require('jade')); + * + * or + * + * app.register('html', require('jade')); + * + * This is also useful for libraries that may not + * match extensions correctly. For example my haml.js + * library is installed from npm as "hamljs" so instead + * of layout.hamljs, we can register the engine as ".haml": + * + * app.register('.haml', require('haml-js')); + * + * @param {String} ext + * @param {Object} obj + * @api public + */ + +exports.register = function(ext, exports) { + if ('.' != ext[0]) ext = '.' + ext; + cache[ext] = exports; +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/.npmignore b/NodeDrawing/node_modules/express/node_modules/connect/.npmignore new file mode 100644 index 0000000..b04a224 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/.npmignore @@ -0,0 +1,11 @@ +*.markdown +*.md +.git* +Makefile +benchmarks/ +docs/ +examples/ +install.sh +support/ +test/ +.DS_Store diff --git a/NodeDrawing/node_modules/express/node_modules/connect/LICENSE b/NodeDrawing/node_modules/express/node_modules/connect/LICENSE new file mode 100644 index 0000000..0c5d22d --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/LICENSE @@ -0,0 +1,24 @@ +(The MIT License) + +Copyright (c) 2010 Sencha Inc. +Copyright (c) 2011 LearnBoost +Copyright (c) 2011 TJ Holowaychuk + +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/NodeDrawing/node_modules/express/node_modules/connect/index.js b/NodeDrawing/node_modules/express/node_modules/connect/index.js new file mode 100644 index 0000000..7477048 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/connect'); \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/connect.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/connect.js new file mode 100644 index 0000000..c413834 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/connect.js @@ -0,0 +1,106 @@ + +/*! + * Connect + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var HTTPServer = require('./http').Server + , HTTPSServer = require('./https').Server + , fs = require('fs'); + +// node patches + +require('./patch'); + +// expose createServer() as the module + +exports = module.exports = createServer; + +/** + * Framework version. + */ + +exports.version = '1.6.2'; + +/** + * Initialize a new `connect.HTTPServer` with the middleware + * passed to this function. When an object is passed _first_, + * we assume these are the tls options, and return a `connect.HTTPSServer`. + * + * Examples: + * + * An example HTTP server, accepting several middleware. + * + * var server = connect.createServer( + * connect.logger() + * , connect.static(__dirname + '/public') + * ); + * + * An HTTPS server, utilizing the same middleware as above. + * + * var server = connect.createServer( + * { key: key, cert: cert } + * , connect.logger() + * , connect.static(__dirname + '/public') + * ); + * + * Alternatively with connect 1.0 we may omit `createServer()`. + * + * connect( + * connect.logger() + * , connect.static(__dirname + '/public') + * ).listen(3000); + * + * @param {Object|Function} ... + * @return {Server} + * @api public + */ + +function createServer() { + if ('object' == typeof arguments[0]) { + return new HTTPSServer(arguments[0], Array.prototype.slice.call(arguments, 1)); + } else { + return new HTTPServer(Array.prototype.slice.call(arguments)); + } +}; + +// support connect.createServer() + +exports.createServer = createServer; + +// auto-load getters + +exports.middleware = {}; + +/** + * Auto-load bundled middleware with getters. + */ + +fs.readdirSync(__dirname + '/middleware').forEach(function(filename){ + if (/\.js$/.test(filename)) { + var name = filename.substr(0, filename.lastIndexOf('.')); + exports.middleware.__defineGetter__(name, function(){ + return require('./middleware/' + name); + }); + } +}); + +// expose utils + +exports.utils = require('./utils'); + +// expose getters as first-class exports + +exports.utils.merge(exports, exports.middleware); + +// expose constructors + +exports.HTTPServer = HTTPServer; +exports.HTTPSServer = HTTPSServer; + diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/http.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/http.js new file mode 100644 index 0000000..52e93e9 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/http.js @@ -0,0 +1,212 @@ + +/*! + * Connect - HTTPServer + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , parse = require('url').parse + , assert = require('assert'); + +// environment + +var env = process.env.NODE_ENV || 'development'; + +/** + * Initialize a new `Server` with the given `middleware`. + * + * Examples: + * + * var server = connect.createServer( + * connect.favicon() + * , connect.logger() + * , connect.static(__dirname + '/public') + * ); + * + * @params {Array} middleware + * @return {Server} + * @api public + */ + +var Server = exports.Server = function HTTPServer(middleware) { + this.stack = []; + middleware.forEach(function(fn){ + this.use(fn); + }, this); + http.Server.call(this, this.handle); +}; + +/** + * Inherit from `http.Server.prototype`. + */ + +Server.prototype.__proto__ = http.Server.prototype; + +/** + * Utilize the given middleware `handle` to the given `route`, + * defaulting to _/_. This "route" is the mount-point for the + * middleware, when given a value other than _/_ the middleware + * is only effective when that segment is present in the request's + * pathname. + * + * For example if we were to mount a function at _/admin_, it would + * be invoked on _/admin_, and _/admin/settings_, however it would + * not be invoked for _/_, or _/posts_. + * + * This is effectively the same as passing middleware to `connect.createServer()`, + * however provides a progressive api. + * + * Examples: + * + * var server = connect.createServer(); + * server.use(connect.favicon()); + * server.use(connect.logger()); + * server.use(connect.static(__dirname + '/public')); + * + * If we wanted to prefix static files with _/public_, we could + * "mount" the `static()` middleware: + * + * server.use('/public', connect.static(__dirname + '/public')); + * + * This api is chainable, meaning the following is valid: + * + * connect.createServer() + * .use(connect.favicon()) + * .use(connect.logger()) + * .use(connect.static(__dirname + '/public')) + * .listen(3000); + * + * @param {String|Function} route or handle + * @param {Function} handle + * @return {Server} + * @api public + */ + +Server.prototype.use = function(route, handle){ + this.route = '/'; + + // default route to '/' + if ('string' != typeof route) { + handle = route; + route = '/'; + } + + // wrap sub-apps + if ('function' == typeof handle.handle) { + var server = handle; + server.route = route; + handle = function(req, res, next) { + server.handle(req, res, next); + }; + } + + // wrap vanilla http.Servers + if (handle instanceof http.Server) { + handle = handle.listeners('request')[0]; + } + + // normalize route to not trail with slash + if ('/' == route[route.length - 1]) { + route = route.substr(0, route.length - 1); + } + + // add the middleware + this.stack.push({ route: route, handle: handle }); + + // allow chaining + return this; +}; + +/** + * Handle server requests, punting them down + * the middleware stack. + * + * @api private + */ + +Server.prototype.handle = function(req, res, out) { + var writeHead = res.writeHead + , stack = this.stack + , removed = '' + , index = 0; + + function next(err) { + var layer, path, c; + req.url = removed + req.url; + req.originalUrl = req.originalUrl || req.url; + removed = ''; + + layer = stack[index++]; + + // all done + if (!layer) { + // but wait! we have a parent + if (out) return out(err); + + // otherwise send a proper error message to the browser. + if (err) { + var msg = 'production' == env + ? 'Internal Server Error' + : err.stack || err.toString(); + + // output to stderr in a non-test env + if ('test' != env) console.error(err.stack || err.toString()); + + res.statusCode = 500; + res.setHeader('Content-Type', 'text/plain'); + res.end(msg); + } else { + res.statusCode = 404; + res.setHeader('Content-Type', 'text/plain'); + res.end('Cannot ' + req.method + ' ' + req.url); + } + return; + } + + try { + path = parse(req.url).pathname; + if (undefined == path) path = '/'; + + // skip this layer if the route doesn't match. + if (0 != path.indexOf(layer.route)) return next(err); + + c = path[layer.route.length]; + if (c && '/' != c && '.' != c) return next(err); + + // Call the layer handler + // Trim off the part of the url that matches the route + removed = layer.route; + req.url = req.url.substr(removed.length); + + // Ensure leading slash + if ('/' != req.url[0]) req.url = '/' + req.url; + + var arity = layer.handle.length; + if (err) { + if (arity === 4) { + layer.handle(err, req, res, next); + } else { + next(err); + } + } else if (arity < 4) { + layer.handle(req, res, next); + } else { + next(); + } + } catch (e) { + if (e instanceof assert.AssertionError) { + console.error(e.stack + '\n'); + next(e); + } else { + next(e); + } + } + } + next(); +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/https.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/https.js new file mode 100644 index 0000000..9b09fa4 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/https.js @@ -0,0 +1,47 @@ + +/*! + * Connect - HTTPServer + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var HTTPServer = require('./http').Server + , https = require('https'); + +/** + * Initialize a new `Server` with the given + *`options` and `middleware`. The HTTPS api + * is identical to the [HTTP](http.html) server, + * however TLS `options` must be provided before + * passing in the optional middleware. + * + * @params {Object} options + * @params {Array} middleawre + * @return {Server} + * @api public + */ + +var Server = exports.Server = function HTTPSServer(options, middleware) { + this.stack = []; + middleware.forEach(function(fn){ + this.use(fn); + }, this); + https.Server.call(this, options, this.handle); +}; + +/** + * Inherit from `http.Server.prototype`. + */ + +Server.prototype.__proto__ = https.Server.prototype; + +// mixin HTTPServer methods + +Object.keys(HTTPServer.prototype).forEach(function(method){ + Server.prototype[method] = HTTPServer.prototype[method]; +}); \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/index.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/index.js new file mode 100644 index 0000000..4865946 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/index.js @@ -0,0 +1,45 @@ + +/** + * # Connect + * + * Connect is a middleware framework for node, + * shipping with over 11 bundled middleware and a rich choice of + * [3rd-party middleware](https://github.com/senchalabs/connect/wiki). + * + * Installation: + * + * $ npm install connect + * + * API: + * + * - [connect](connect.html) general + * - [http](http.html) http server + * - [https](https.html) https server + * + * Middleware: + * + * - [logger](middleware-logger.html) request logger with custom format support + * - [csrf](middleware-csrf.html) Cross-site request forgery protection + * - [basicAuth](middleware-basicAuth.html) basic http authentication + * - [bodyParser](middleware-bodyParser.html) extensible request body parser + * - [cookieParser](middleware-cookieParser.html) cookie parser + * - [session](middleware-session.html) session management support with bundled [MemoryStore](middleware-session-memory.html) + * - [compiler](middleware-compiler.html) static asset compiler (sass, less, coffee-script, etc) + * - [methodOverride](middleware-methodOverride.html) faux HTTP method support + * - [responseTime](middleware-responseTime.html) calculates response-time and exposes via X-Response-Time + * - [router](middleware-router.html) provides rich Sinatra / Express-like routing + * - [static](middleware-static.html) streaming static file server supporting `Range` and more + * - [directory](middleware-directory.html) directory listing middleware + * - [vhost](middleware-vhost.html) virtual host sub-domain mapping middleware + * - [favicon](middleware-favicon.html) efficient favicon server (with default icon) + * - [limit](middleware-limit.html) limit the bytesize of request bodies + * - [profiler](middleware-profiler.html) request profiler reporting response-time, memory usage, etc + * - [query](middleware-query.html) automatic querystring parser, populating `req.query` + * - [errorHandler](middleware-errorHandler.html) flexible error handler + * + * Internals: + * + * - connect [utilities](utils.html) + * - node monkey [patches](patch.html) + * + */ \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js new file mode 100644 index 0000000..3ff472b --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js @@ -0,0 +1,93 @@ + +/*! + * Connect - basicAuth + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , unauthorized = utils.unauthorized + , badRequest = utils.badRequest; + +/** + * Enfore basic authentication by providing a `callback(user, pass)`, + * which must return `true` in order to gain access. Alternatively an async + * method is provided as well, invoking `callback(user, pass, callback)`. Populates + * `req.remoteUser`. The final alternative is simply passing username / password + * strings. + * + * Examples: + * + * connect(connect.basicAuth('username', 'password')); + * + * connect( + * connect.basicAuth(function(user, pass){ + * return 'tj' == user & 'wahoo' == pass; + * }) + * ); + * + * connect( + * connect.basicAuth(function(user, pass, fn){ + * User.authenticate({ user: user, pass: pass }, fn); + * }) + * ); + * + * @param {Function|String} callback or username + * @param {String} realm + * @api public + */ + +module.exports = function basicAuth(callback, realm) { + var username, password; + + // user / pass strings + if ('string' == typeof callback) { + username = callback; + password = realm; + if ('string' != typeof password) throw new Error('password argument required'); + realm = arguments[2]; + callback = function(user, pass){ + return user == username && pass == password; + } + } + + realm = realm || 'Authorization Required'; + + return function(req, res, next) { + var authorization = req.headers.authorization; + + if (req.remoteUser) return next(); + if (!authorization) return unauthorized(res, realm); + + var parts = authorization.split(' ') + , scheme = parts[0] + , credentials = new Buffer(parts[1], 'base64').toString().split(':'); + + if ('Basic' != scheme) return badRequest(res); + + // async + if (callback.length >= 3) { + var pause = utils.pause(req); + callback(credentials[0], credentials[1], function(err, user){ + if (err || !user) return unauthorized(res, realm); + req.remoteUser = user; + next(); + pause.resume(); + }); + // sync + } else { + if (callback(credentials[0], credentials[1])) { + req.remoteUser = credentials[0]; + next(); + } else { + unauthorized(res, realm); + } + } + } +}; + diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js new file mode 100644 index 0000000..5e6f3ef --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js @@ -0,0 +1,92 @@ + +/*! + * Connect - bodyParser + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var qs = require('qs'); + +/** + * Extract the mime type from the given request's + * _Content-Type_ header. + * + * @param {IncomingMessage} req + * @return {String} + * @api private + */ + +function mime(req) { + var str = req.headers['content-type'] || ''; + return str.split(';')[0]; +} + +/** + * Parse request bodies. + * + * By default _application/json_ and _application/x-www-form-urlencoded_ + * are supported, however you may map `connect.bodyParser.parse[contentType]` + * to a function of your choice to replace existing parsers, or implement + * one for other content-types. + * + * Examples: + * + * connect.createServer( + * connect.bodyParser() + * , function(req, res) { + * res.end('viewing user ' + req.body.user.name); + * } + * ); + * + * Since both _json_ and _x-www-form-urlencoded_ are supported by + * default, either of the following requests would result in the response + * of "viewing user tj". + * + * $ curl -d 'user[name]=tj' http://localhost/ + * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://localhost/ + * + * @return {Function} + * @api public + */ + +exports = module.exports = function bodyParser(){ + return function bodyParser(req, res, next) { + if ('GET' == req.method || 'HEAD' == req.method) return next(); + var parser = exports.parse[mime(req)]; + if (parser && !req.body) { + var data = ''; + req.setEncoding('utf8'); + req.on('data', function(chunk) { data += chunk; }); + req.on('end', function(){ + req.rawBody = data; + try { + req.body = data + ? parser(data) + : {}; + } catch (err) { + return next(err); + } + next(); + }); + } else { + next(); + } + } +}; + +/** + * Supported decoders. + * + * - application/x-www-form-urlencoded + * - application/json + */ + +exports.parse = { + 'application/x-www-form-urlencoded': qs.parse + , 'application/json': JSON.parse +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/compiler.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/compiler.js new file mode 100644 index 0000000..dc4dd66 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/compiler.js @@ -0,0 +1,163 @@ + +/*! + * Connect - compiler + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , path = require('path') + , parse = require('url').parse; + +/** + * Require cache. + */ + +var cache = {}; + +/** + * Setup compiler. + * + * Options: + * + * - `src` Source directory, defaults to **CWD**. + * - `dest` Destination directory, defaults `src`. + * - `enable` Array of enabled compilers. + * + * Compilers: + * + * - `sass` Compiles sass to css + * - `less` Compiles less to css + * - `coffeescript` Compiles coffee to js + * + * @param {Object} options + * @api public + */ + +exports = module.exports = function compiler(options){ + options = options || {}; + + var srcDir = options.src || process.cwd() + , destDir = options.dest || srcDir + , enable = options.enable; + + if (!enable || enable.length === 0) { + throw new Error('compiler\'s "enable" option is not set, nothing will be compiled.'); + } + + return function compiler(req, res, next){ + if ('GET' != req.method) return next(); + var pathname = parse(req.url).pathname; + for (var i = 0, len = enable.length; i < len; ++i) { + var name = enable[i] + , compiler = compilers[name]; + if (compiler.match.test(pathname)) { + var src = (srcDir + pathname).replace(compiler.match, compiler.ext) + , dest = destDir + pathname; + + // Compare mtimes + fs.stat(src, function(err, srcStats){ + if (err) { + if ('ENOENT' == err.code) { + next(); + } else { + next(err); + } + } else { + fs.stat(dest, function(err, destStats){ + if (err) { + // Oh snap! it does not exist, compile it + if ('ENOENT' == err.code) { + compile(); + } else { + next(err); + } + } else { + // Source has changed, compile it + if (srcStats.mtime > destStats.mtime) { + compile(); + } else { + // Defer file serving + next(); + } + } + }); + } + }); + + // Compile to the destination + function compile() { + fs.readFile(src, 'utf8', function(err, str){ + if (err) { + next(err); + } else { + compiler.compile(str, function(err, str){ + if (err) { + next(err); + } else { + fs.writeFile(dest, str, 'utf8', function(err){ + next(err); + }); + } + }); + } + }); + } + return; + } + } + next(); + }; +}; + +/** + * Bundled compilers: + * + * - [sass](http://github.com/visionmedia/sass.js) to _css_ + * - [less](http://github.com/cloudhead/less.js) to _css_ + * - [coffee](http://github.com/jashkenas/coffee-script) to _js_ + */ + +var compilers = exports.compilers = { + sass: { + match: /\.css$/, + ext: '.sass', + compile: function(str, fn){ + var sass = cache.sass || (cache.sass = require('sass')); + try { + fn(null, sass.render(str)); + } catch (err) { + fn(err); + } + } + }, + less: { + match: /\.css$/, + ext: '.less', + compile: function(str, fn){ + var less = cache.less || (cache.less = require('less')); + try { + less.render(str, fn); + } catch (err) { + fn(err); + } + } + }, + coffeescript: { + match: /\.js$/, + ext: '.coffee', + compile: function(str, fn){ + var coffee = cache.coffee || (cache.coffee = require('coffee-script')); + try { + fn(null, coffee.compile(str)); + } catch (err) { + fn(err); + } + } + } +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js new file mode 100644 index 0000000..d6b69de --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js @@ -0,0 +1,46 @@ + +/*! + * Connect - cookieParser + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('./../utils'); + +/** + * Parse _Cookie_ header and populate `req.cookies` + * with an object keyed by the cookie names. + * + * Examples: + * + * connect.createServer( + * connect.cookieParser() + * , function(req, res, next){ + * res.end(JSON.stringify(req.cookies)); + * } + * ); + * + * @return {Function} + * @api public + */ + +module.exports = function cookieParser(){ + return function cookieParser(req, res, next) { + var cookie = req.headers.cookie; + if (req.cookies) return next(); + req.cookies = {}; + if (cookie) { + try { + req.cookies = utils.parseCookie(cookie); + } catch (err) { + return next(err); + } + } + next(); + }; +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/csrf.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/csrf.js new file mode 100644 index 0000000..1dcf0d1 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/csrf.js @@ -0,0 +1,105 @@ + +/*! + * Connect - csrf + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , crypto = require('crypto'); + +/** + * CRSF protection middleware. + * + * By default this middleware generates a token named "_csrf" + * which should be added to requests which mutate + * state, within a hidden form field, query-string etc. This + * token is validated against the visitor's `req.session._csrf` + * property which is re-generated per request. + * + * The default `value` function checks `req.body` generated + * by the `bodyParser()` middleware, `req.query` generated + * by `query()`, and the "X-CSRF-Token" header field. + * + * This middleware requires session support, thus should be added + * somewhere _below_ `session()` and `cookieParser()`. + * + * Examples: + * + * var form = '\n\ + *
\n\ + * \n\ + * \n\ + * \n\ + * \n\ + *
\n\ + * '; + * + * connect( + * connect.cookieParser() + * , connect.session({ secret: 'keyboard cat' }) + * , connect.bodyParser() + * , connect.csrf() + * + * , function(req, res, next){ + * if ('POST' != req.method) return next(); + * req.session.user = req.body.user; + * next(); + * } + * + * , function(req, res){ + * res.setHeader('Content-Type', 'text/html'); + * var body = form + * .replace('{token}', req.session._csrf) + * .replace('{user}', req.session.user && req.session.user.name || ''); + * res.end(body); + * } + * ).listen(3000); + * + * Options: + * + * - `value` a function accepting the request, returning the token + * + * @param {Object} options + * @api public + */ + +module.exports = function csrf(options) { + var options = options || {} + , value = options.value || defaultValue; + + return function(req, res, next){ + // generate CSRF token + var token = req.session._csrf || (req.session._csrf = utils.uid(24)); + + // ignore GET (for now) + if ('GET' == req.method) return next(); + + // determine value + var val = value(req); + + // check + if (val != token) return utils.forbidden(res); + + next(); + } +}; + +/** + * Default value function, checking the `req.body` + * and `req.query` for the CSRF token. + * + * @param {IncomingMessage} req + * @return {String} + * @api private + */ + +function defaultValue(req) { + return (req.body && req.body._csrf) + || (req.query && req.query._csrf) + || (req.headers['x-csrf-token']); +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/directory.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/directory.js new file mode 100644 index 0000000..df5b5e6 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/directory.js @@ -0,0 +1,222 @@ + +/*! + * Connect - directory + * Copyright(c) 2011 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +// TODO: icon / style for directories +// TODO: arrow key navigation +// TODO: make icons extensible + +/** + * Module dependencies. + */ + +var fs = require('fs') + , parse = require('url').parse + , utils = require('../utils') + , path = require('path') + , normalize = path.normalize + , extname = path.extname + , join = path.join; + +/** + * Icon cache. + */ + +var cache = {}; + +/** + * Serve directory listings with the given `root` path. + * + * Options: + * + * - `hidden` display hidden (dot) files. Defaults to false. + * - `icons` display icons. Defaults to false. + * - `filter` Apply this filter function to files. Defaults to false. + * + * @param {String} root + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function directory(root, options){ + options = options || {}; + + // root required + if (!root) throw new Error('directory() root path required'); + var hidden = options.hidden + , icons = options.icons + , filter = options.filter + , root = normalize(root); + + return function directory(req, res, next) { + var accept = req.headers.accept || 'text/plain' + , url = parse(req.url) + , dir = decodeURIComponent(url.pathname) + , path = normalize(join(root, dir)) + , originalUrl = parse(req.originalUrl) + , originalDir = decodeURIComponent(originalUrl.pathname) + , showUp = path != root && path != root + '/'; + + // null byte(s) + if (~path.indexOf('\0')) return utils.badRequest(res); + + // malicious path + if (0 != path.indexOf(root)) return utils.forbidden(res); + + // check if we have a directory + fs.stat(path, function(err, stat){ + if (err) return 'ENOENT' == err.code + ? next() + : next(err); + + if (!stat.isDirectory()) return next(); + + // fetch files + fs.readdir(path, function(err, files){ + if (err) return next(err); + if (!hidden) files = removeHidden(files); + if (filter) files = files.filter(filter); + files.sort(); + // content-negotiation + for (var key in exports) { + if (~accept.indexOf(key) || ~accept.indexOf('*/*')) { + exports[key](req, res, files, next, originalDir, showUp, icons); + return; + } + } + utils.notAcceptable(res); + }); + }); + }; +}; + +/** + * Respond with text/html. + */ + +exports.html = function(req, res, files, next, dir, showUp, icons){ + fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){ + if (err) return next(err); + fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){ + if (err) return next(err); + if (showUp) files.unshift('..'); + str = str + .replace('{style}', style) + .replace('{files}', html(files, dir, icons)) + .replace('{directory}', dir) + .replace('{linked-path}', htmlPath(dir)); + res.setHeader('Content-Type', 'text/html'); + res.setHeader('Content-Length', str.length); + res.end(str); + }); + }); +}; + +/** + * Respond with application/json. + */ + +exports.json = function(req, res, files){ + files = JSON.stringify(files); + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Content-Length', files.length); + res.end(files); +}; + +/** + * Respond with text/plain. + */ + +exports.plain = function(req, res, files){ + files = files.join('\n') + '\n'; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Length', files.length); + res.end(files); +}; + +/** + * Map html `dir`, returning a linked path. + */ + +function htmlPath(dir) { + var curr = []; + return dir.split('/').map(function(part){ + curr.push(part); + return '' + part + ''; + }).join(' / '); +} + +/** + * Map html `files`, returning an html unordered list. + */ + +function html(files, dir, useIcons) { + return '
    ' + files.map(function(file){ + var icon = '' + , classes = []; + + if (useIcons && '..' != file) { + icon = icons[extname(file)] || icons.default; + icon = ''; + classes.push('icon'); + } + + return '
  • ' + + icon + file + '
  • '; + + }).join('\n') + '
'; +} + +/** + * Load and cache the given `icon`. + * + * @param {String} icon + * @return {String} + * @api private + */ + +function load(icon) { + if (cache[icon]) return cache[icon]; + return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64'); +} + +/** + * Filter "hidden" `files`, aka files + * beginning with a `.`. + * + * @param {Array} files + * @return {Array} + * @api private + */ + +function removeHidden(files) { + return files.filter(function(file){ + return '.' != file[0]; + }); +} + +/** + * Icon map. + */ + +var icons = { + '.js': 'page_white_code_red.png' + , '.c': 'page_white_c.png' + , '.h': 'page_white_h.png' + , '.cc': 'page_white_cplusplus.png' + , '.php': 'page_white_php.png' + , '.rb': 'page_white_ruby.png' + , '.cpp': 'page_white_cplusplus.png' + , '.swf': 'page_white_flash.png' + , '.pdf': 'page_white_acrobat.png' + , 'default': 'page_white.png' +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js new file mode 100644 index 0000000..f2fc44f --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js @@ -0,0 +1,100 @@ +/*! + * Connect - errorHandler + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , url = require('url') + , fs = require('fs'); + +/** + * Flexible error handler, providing (_optional_) stack traces + * and error message responses for requests accepting text, html, + * or json. + * + * Options: + * + * - `showStack`, `stack` respond with both the error message and stack trace. Defaults to `false` + * - `showMessage`, `message`, respond with the exception message only. Defaults to `false` + * - `dumpExceptions`, `dump`, dump exceptions to stderr (without terminating the process). Defaults to `false` + * + * Text: + * + * By default, and when _text/plain_ is accepted a simple stack trace + * or error message will be returned. + * + * JSON: + * + * When _application/json_ is accepted, connect will respond with + * an object in the form of `{ "error": error }`. + * + * HTML: + * + * When accepted connect will output a nice html stack trace. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function errorHandler(options){ + options = options || {}; + + // defaults + var showStack = options.showStack || options.stack + , showMessage = options.showMessage || options.message + , dumpExceptions = options.dumpExceptions || options.dump + , formatUrl = options.formatUrl; + + return function errorHandler(err, req, res, next){ + res.statusCode = 500; + if (dumpExceptions) console.error(err.stack); + if (showStack) { + var accept = req.headers.accept || ''; + // html + if (~accept.indexOf('html')) { + fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){ + fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){ + var stack = (err.stack || '') + .split('\n').slice(1) + .map(function(v){ return '
  • ' + v + '
  • '; }).join(''); + html = html + .replace('{style}', style) + .replace('{stack}', stack) + .replace('{title}', exports.title) + .replace(/\{error\}/g, utils.escape(err.toString())); + res.setHeader('Content-Type', 'text/html'); + res.end(html); + }); + }); + // json + } else if (~accept.indexOf('json')) { + var json = JSON.stringify({ error: err }); + res.setHeader('Content-Type', 'application/json'); + res.end(json); + // plain text + } else { + res.writeHead(500, { 'Content-Type': 'text/plain' }); + res.end(err.stack); + } + } else { + var body = showMessage + ? err.toString() + : 'Internal Server Error'; + res.setHeader('Content-Type', 'text/plain'); + res.end(body); + } + }; +}; + +/** + * Template title. + */ + +exports.title = 'Connect'; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/favicon.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/favicon.js new file mode 100644 index 0000000..8eeafba --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/favicon.js @@ -0,0 +1,76 @@ + +/*! + * Connect - favicon + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , utils = require('../utils'); + +/** + * Favicon cache. + */ + +var icon; + +/** + * By default serves the connect favicon, or the favicon + * located by the given `path`. + * + * Options: + * + * - `maxAge` cache-control max-age directive, defaulting to 1 day + * + * Examples: + * + * connect.createServer( + * connect.favicon() + * ); + * + * connect.createServer( + * connect.favicon(__dirname + '/public/favicon.ico') + * ); + * + * @param {String} path + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function favicon(path, options){ + var options = options || {} + , path = path || __dirname + '/../public/favicon.ico' + , maxAge = options.maxAge || 86400000; + + return function favicon(req, res, next){ + if ('/favicon.ico' == req.url) { + if (icon) { + res.writeHead(200, icon.headers); + res.end(icon.body); + } else { + fs.readFile(path, function(err, buf){ + if (err) return next(err); + icon = { + headers: { + 'Content-Type': 'image/x-icon' + , 'Content-Length': buf.length + , 'ETag': '"' + utils.md5(buf) + '"' + , 'Cache-Control': 'public, max-age=' + (maxAge / 1000) + }, + body: buf + }; + res.writeHead(200, icon.headers); + res.end(icon.body); + }); + } + } else { + next(); + } + }; +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/limit.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/limit.js new file mode 100644 index 0000000..3bff0cc --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/limit.js @@ -0,0 +1,78 @@ + +/*! + * Connect - limit + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Limit request bodies to the given size in `bytes`. + * + * A string representation of the bytesize may also be passed, + * for example "5mb", "200kb", "1gb", etc. + * + * Examples: + * + * var server = connect( + * connect.limit('5.5mb') + * ).listen(3000); + * + * TODO: pause EV_READ + * + * @param {Number|String} bytes + * @return {Function} + * @api public + */ + +module.exports = function limit(bytes){ + if ('string' == typeof bytes) bytes = parse(bytes); + if ('number' != typeof bytes) throw new Error('limit() bytes required'); + return function limit(req, res, next){ + var received = 0 + , len = req.headers['content-length'] + ? parseInt(req.headers['content-length'], 10) + : null; + + // deny the request + function deny() { + req.destroy(); + } + + // self-awareness + if (req._limit) return next(); + req._limit = true; + + // limit by content-length + if (len && len > bytes) deny(); + + // limit + req.on('data', function(chunk){ + received += chunk.length; + if (received > bytes) deny(); + }); + + next(); + }; +}; + +/** + * Parse byte `size` string. + * + * @param {String} size + * @return {Number} + * @api private + */ + +function parse(size) { + var parts = size.match(/^(\d+(?:\.\d+)?) *(kb|mb|gb)$/) + , n = parseFloat(parts[1]) + , type = parts[2]; + + var map = { + kb: 1024 + , mb: 1024 * 1024 + , gb: 1024 * 1024 * 1024 + }; + + return map[type] * n; +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/logger.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/logger.js new file mode 100644 index 0000000..75cc5aa --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/logger.js @@ -0,0 +1,299 @@ + +/*! + * Connect - logger + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Log buffer. + */ + +var buf = []; + +/** + * Default log buffer duration. + */ + +var defaultBufferDuration = 1000; + +/** + * Log requests with the given `options` or a `format` string. + * + * Options: + * + * - `format` Format string, see below for tokens + * - `stream` Output stream, defaults to _stdout_ + * - `buffer` Buffer duration, defaults to 1000ms when _true_ + * - `immediate` Write log line on request instead of response (for response times) + * + * Tokens: + * + * - `:req[header]` ex: `:req[Accept]` + * - `:res[header]` ex: `:res[Content-Length]` + * - `:http-version` + * - `:response-time` + * - `:remote-addr` + * - `:date` + * - `:method` + * - `:url` + * - `:referrer` + * - `:user-agent` + * - `:status` + * + * Formats: + * + * Pre-defined formats that ship with connect: + * + * - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"' + * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms' + * - `tiny` ':method :url :status :res[content-length] - :response-time ms' + * - `dev` concise output colored by response status for development use + * + * Examples: + * + * connect.logger() // default + * connect.logger('short') + * connect.logger('tiny') + * connect.logger('dev') + * connect.logger(':method :url - :referrer') + * connect.logger(':req[content-type] -> :res[content-type]') + * connect.logger(function(req, res){ return 'some format string' }) + * + * Defining Tokens: + * + * To define a token, simply invoke `connect.logger.token()` with the + * name and a callback function. The value returned is then available + * as ":type" in this case. + * + * connect.logger.token('type', function(req, res){ return req.headers['content-type']; }) + * + * Defining Formats: + * + * All default formats are defined this way, however it's public API as well: + * + * connect.logger.format('name', 'string or function') + * + * @param {String|Function|Object} format or options + * @return {Function} + * @api public + */ + +exports = module.exports = function logger(options) { + if ('object' == typeof options) { + options = options || {}; + } else if (options) { + options = { format: options }; + } else { + options = {}; + } + + // output on request instead of response + var immediate = options.immediate; + + // format name + var fmt = exports[options.format] || options.format || exports.default; + + // compile format + if ('function' != typeof fmt) fmt = compile(fmt); + + // options + var stream = options.stream || process.stdout + , buffer = options.buffer; + + // buffering support + if (buffer) { + var realStream = stream + , interval = 'number' == typeof buffer + ? buffer + : defaultBufferDuration; + + // flush interval + setInterval(function(){ + if (buf.length) { + realStream.write(buf.join(''), 'ascii'); + buf.length = 0; + } + }, interval); + + // swap the stream + stream = { + write: function(str){ + buf.push(str); + } + }; + } + + return function logger(req, res, next) { + req._startTime = new Date; + + // mount safety + if (req._logging) return next(); + + // flag as logging + req._logging = true; + + // immediate + if (immediate) { + var line = fmt(exports, req, res); + if (null == line) return; + stream.write(line + '\n', 'ascii'); + } else { + // proxy end to output loggging + var end = res.end; + res.end = function(chunk, encoding){ + res.end = end; + res.end(chunk, encoding); + var line = fmt(exports, req, res); + if (null == line) return; + stream.write(line + '\n', 'ascii'); + }; + } + + + next(); + }; +}; + +/** + * Compile `fmt` into a function. + * + * @param {String} fmt + * @return {Function} + * @api private + */ + +function compile(fmt) { + fmt = fmt.replace(/"/g, '\\"'); + var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){ + return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "'; + }) + '";' + return new Function('tokens, req, res', js); +}; + +/** + * Define a token function with the given `name`, + * and callback `fn(req, res)`. + * + * @param {String} name + * @param {Function} fn + * @return {Object} exports for chaining + * @api public + */ + +exports.token = function(name, fn) { + exports[name] = fn; + return this; +}; + +/** + * Define a `fmt` with the given `name`. + * + * @param {String} name + * @param {String|Function} fmt + * @return {Object} exports for chaining + * @api public + */ + +exports.format = function(name, str){ + exports[name] = str; + return this; +}; + +// default format + +exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'); + +// short format + +exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'); + +// tiny format + +exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms'); + +// dev (colored) + +exports.format('dev', function(tokens, req, res){ + var status = res.statusCode + , color = 32; + + if (status >= 500) color = 31 + else if (status >= 400) color = 33 + else if (status >= 300) color = 36; + + return '\033[90m' + req.method + + ' ' + req.originalUrl + ' ' + + '\033[' + color + 'm' + res.statusCode + + ' \033[90m' + + (new Date - req._startTime) + + 'ms\033[0m'; +}); + +// request url + +exports.token('url', function(req){ + return req.originalUrl; +}); + +// request method + +exports.token('method', function(req){ + return req.method; +}); + +// response time in milliseconds + +exports.token('response-time', function(req){ + return new Date - req._startTime; +}); + +// UTC date + +exports.token('date', function(){ + return new Date().toUTCString(); +}); + +// response status code + +exports.token('status', function(req, res){ + return res.statusCode; +}); + +// normalized referrer + +exports.token('referrer', function(req){ + return req.headers['referer'] || req.headers['referrer']; +}); + +// remote address + +exports.token('remote-addr', function(req){ + return req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress)); +}); + +// HTTP version + +exports.token('http-version', function(req){ + return req.httpVersionMajor + '.' + req.httpVersionMinor; +}); + +// UA string + +exports.token('user-agent', function(req){ + return req.headers['user-agent']; +}); + +// request header + +exports.token('req', function(req, res, field){ + return req.headers[field.toLowerCase()]; +}); + +// response header + +exports.token('res', function(req, res, field){ + return (res._headers || {})[field.toLowerCase()]; +}); + diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js new file mode 100644 index 0000000..db4e9f3 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js @@ -0,0 +1,38 @@ + +/*! + * Connect - methodOverride + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Provides faux HTTP method support. + * + * Pass an optional `key` to use when checking for + * a method override, othewise defaults to _\_method_. + * The original method is available via `req.originalMethod`. + * + * @param {String} key + * @return {Function} + * @api public + */ + +module.exports = function methodOverride(key){ + key = key || "_method"; + return function methodOverride(req, res, next) { + req.originalMethod = req.originalMethod || req.method; + + // req.body + if (req.body && key in req.body) { + req.method = req.body[key].toUpperCase(); + delete req.body[key]; + // check X-HTTP-Method-Override + } else if (req.headers['x-http-method-override']) { + req.method = req.headers['x-http-method-override'].toUpperCase(); + } + + next(); + }; +}; + diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/profiler.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/profiler.js new file mode 100644 index 0000000..b0b5bac --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/profiler.js @@ -0,0 +1,100 @@ + +/*! + * Connect - profiler + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Profile the duration of a request. + * + * Typically this middleware should be utilized + * _above_ all others, as it proxies the `res.end()` + * method, being first allows it to encapsulate all + * other middleware. + * + * Example Output: + * + * GET / + * response time 2ms + * memory rss 52.00kb + * memory vsize 2.07mb + * heap before 3.76mb / 8.15mb + * heap after 3.80mb / 8.15mb + * + * @api public + */ + +module.exports = function profiler(){ + return function(req, res, next){ + var end = res.end + , start = snapshot(); + + // state snapshot + function snapshot() { + return { + mem: process.memoryUsage() + , time: new Date + }; + } + + // proxy res.end() + res.end = function(data, encoding){ + res.end = end; + res.end(data, encoding); + compare(req, start, snapshot()) + }; + + next(); + } +}; + +/** + * Compare `start` / `end` snapshots. + * + * @param {IncomingRequest} req + * @param {Object} start + * @param {Object} end + * @api private + */ + +function compare(req, start, end) { + console.log(); + row(req.method, req.url); + row('response time:', (end.time - start.time) + 'ms'); + row('memory rss:', formatBytes(end.mem.rss - start.mem.rss)); + row('memory vsize:', formatBytes(end.mem.vsize - start.mem.vsize)); + row('heap before:', formatBytes(start.mem.heapUsed) + ' / ' + formatBytes(start.mem.heapTotal)); + row('heap after:', formatBytes(end.mem.heapUsed) + ' / ' + formatBytes(end.mem.heapTotal)); + console.log(); +} + +/** + * Row helper + * + * @param {String} key + * @param {String} val + * @api private + */ + +function row(key, val) { + console.log(' \033[90m%s\033[0m \033[36m%s\033[0m', key, val); +} + +/** + * Format byte-size. + * + * @param {Number} bytes + * @return {String} + * @api private + */ + +function formatBytes(bytes) { + var kb = 1024 + , mb = 1024 * kb + , gb = 1024 * mb; + if (bytes < kb) return bytes + 'b'; + if (bytes < mb) return (bytes / kb).toFixed(2) + 'kb'; + if (bytes < gb) return (bytes / mb).toFixed(2) + 'mb'; + return (bytes / gb).toFixed(2) + 'gb'; +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/query.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/query.js new file mode 100644 index 0000000..d3b1acd --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/query.js @@ -0,0 +1,40 @@ + +/*! + * Connect - query + * Copyright(c) 2011 TJ Holowaychuk + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var qs = require('qs') + , parse = require('url').parse; + +/** + * Automatically parse the query-string when available, + * populating the `req.query` object. + * + * Examples: + * + * connect( + * connect.query() + * , function(req, res){ + * res.end(JSON.stringify(req.query)); + * } + * ).listen(3000); + * + * @return {Function} + * @api public + */ + +module.exports = function query(){ + return function query(req, res, next){ + req.query = ~req.url.indexOf('?') + ? qs.parse(parse(req.url).query) + : {}; + next(); + }; +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/responseTime.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/responseTime.js new file mode 100644 index 0000000..2b2133a --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/responseTime.js @@ -0,0 +1,34 @@ + +/*! + * Connect - responseTime + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Adds the `X-Response-Time` header displaying the response + * duration in milliseconds. + * + * @return {Function} + * @api public + */ + +module.exports = function responseTime(){ + return function(req, res, next){ + var writeHead = res.writeHead + , start = new Date; + + if (res._responseTime) return next(); + res._responseTime = true; + + // proxy writeHead to calculate duration + res.writeHead = function(status, headers){ + var duration = new Date - start; + res.setHeader('X-Response-Time', duration + 'ms'); + res.writeHead = writeHead; + res.writeHead(status, headers); + }; + + next(); + }; +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/router.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/router.js new file mode 100644 index 0000000..a07452e --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/router.js @@ -0,0 +1,379 @@ + +/*! + * Connect - router + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , parse = require('url').parse; + +/** + * Expose router. + */ + +exports = module.exports = router; + +/** + * Supported HTTP / WebDAV methods. + */ + +var _methods = exports.methods = [ + 'get' + , 'post' + , 'put' + , 'delete' + , 'connect' + , 'options' + , 'trace' + , 'copy' + , 'lock' + , 'mkcol' + , 'move' + , 'propfind' + , 'proppatch' + , 'unlock' + , 'report' + , 'mkactivity' + , 'checkout' + , 'merge' +]; + +/** + * Provides Sinatra and Express-like routing capabilities. + * + * Examples: + * + * connect.router(function(app){ + * app.get('/user/:id', function(req, res, next){ + * // populates req.params.id + * }); + * app.put('/user/:id', function(req, res, next){ + * // populates req.params.id + * }); + * }) + * + * @param {Function} fn + * @return {Function} + * @api public + */ + +function router(fn){ + var self = this + , methods = {} + , routes = {} + , params = {}; + + if (!fn) throw new Error('router provider requires a callback function'); + + // Generate method functions + _methods.forEach(function(method){ + methods[method] = generateMethodFunction(method.toUpperCase()); + }); + + // Alias del -> delete + methods.del = methods.delete; + + // Apply callback to all methods + methods.all = function(){ + var args = arguments; + _methods.forEach(function(name){ + methods[name].apply(this, args); + }); + return self; + }; + + // Register param callback + methods.param = function(name, fn){ + params[name] = fn; + }; + + fn.call(this, methods); + + function generateMethodFunction(name) { + var localRoutes = routes[name] = routes[name] || []; + return function(path, fn){ + var keys = [] + , middleware = []; + + // slice middleware + if (arguments.length > 2) { + middleware = Array.prototype.slice.call(arguments, 1, arguments.length); + fn = middleware.pop(); + middleware = utils.flatten(middleware); + } + + fn.middleware = middleware; + + if (!path) throw new Error(name + ' route requires a path'); + if (!fn) throw new Error(name + ' route ' + path + ' requires a callback'); + var regexp = path instanceof RegExp + ? path + : normalizePath(path, keys); + localRoutes.push({ + fn: fn + , path: regexp + , keys: keys + , orig: path + , method: name + }); + return self; + }; + } + + function router(req, res, next){ + var route + , self = this; + + (function pass(i){ + if (route = match(req, routes, i)) { + var i = 0 + , keys = route.keys; + + req.params = route.params; + + // Param preconditions + (function param(err) { + try { + var key = keys[i++] + , val = req.params[key] + , fn = params[key]; + + if ('route' == err) { + pass(req._route_index + 1); + // Error + } else if (err) { + next(err); + // Param has callback + } else if (fn) { + // Return style + if (1 == fn.length) { + req.params[key] = fn(val); + param(); + // Middleware style + } else { + fn(req, res, param, val); + } + // Finished processing params + } else if (!key) { + // route middleware + i = 0; + (function nextMiddleware(err){ + var fn = route.middleware[i++]; + if ('route' == err) { + pass(req._route_index + 1); + } else if (err) { + next(err); + } else if (fn) { + fn(req, res, nextMiddleware); + } else { + route.call(self, req, res, function(err){ + if (err) { + next(err); + } else { + pass(req._route_index + 1); + } + }); + } + })(); + // More params + } else { + param(); + } + } catch (err) { + next(err); + } + })(); + } else if ('OPTIONS' == req.method) { + options(req, res, routes); + } else { + next(); + } + })(); + }; + + router.remove = function(path, method){ + var fns = router.lookup(path, method); + fns.forEach(function(fn){ + routes[fn.method].splice(fn.index, 1); + }); + }; + + router.lookup = function(path, method, ret){ + ret = ret || []; + + // method specific lookup + if (method) { + method = method.toUpperCase(); + if (routes[method]) { + routes[method].forEach(function(route, i){ + if (path == route.orig) { + var fn = route.fn; + fn.regexp = route.path; + fn.keys = route.keys; + fn.path = route.orig; + fn.method = route.method; + fn.index = i; + ret.push(fn); + } + }); + } + // global lookup + } else { + _methods.forEach(function(method){ + router.lookup(path, method, ret); + }); + } + + return ret; + }; + + router.match = function(url, method, ret){ + var ret = ret || [] + , i = 0 + , fn + , req; + + // method specific matches + if (method) { + method = method.toUpperCase(); + req = { url: url, method: method }; + while (fn = match(req, routes, i)) { + i = req._route_index + 1; + ret.push(fn); + } + // global matches + } else { + _methods.forEach(function(method){ + router.match(url, method, ret); + }); + } + + return ret; + }; + + return router; +} + +/** + * Respond to OPTIONS. + * + * @param {ServerRequest} req + * @param {ServerResponse} req + * @param {Array} routes + * @api private + */ + +function options(req, res, routes) { + var pathname = parse(req.url).pathname + , body = optionsFor(pathname, routes).join(','); + res.writeHead(200, { + 'Content-Length': body.length + , 'Allow': body + }); + res.end(body); +} + +/** + * Return OPTIONS array for the given `path`, matching `routes`. + * + * @param {String} path + * @param {Array} routes + * @return {Array} + * @api private + */ + +function optionsFor(path, routes) { + return _methods.filter(function(method){ + var arr = routes[method.toUpperCase()]; + for (var i = 0, len = arr.length; i < len; ++i) { + if (arr[i].path.test(path)) return true; + } + }).map(function(method){ + return method.toUpperCase(); + }); +} + +/** + * Normalize the given path string, + * returning a regular expression. + * + * An empty array should be passed, + * which will contain the placeholder + * key names. For example "/user/:id" will + * then contain ["id"]. + * + * @param {String} path + * @param {Array} keys + * @return {RegExp} + * @api private + */ + +function normalizePath(path, keys) { + path = path + .concat('/?') + .replace(/\/\(/g, '(?:/') + .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){ + keys.push(key); + slash = slash || ''; + return '' + + (optional ? '' : slash) + + '(?:' + + (optional ? slash : '') + + (format || '') + (capture || '([^/]+?)') + ')' + + (optional || ''); + }) + .replace(/([\/.])/g, '\\$1') + .replace(/\*/g, '(.+)'); + return new RegExp('^' + path + '$', 'i'); +} + +/** + * Attempt to match the given request to + * one of the routes. When successful + * a route function is returned. + * + * @param {ServerRequest} req + * @param {Object} routes + * @return {Function} + * @api private + */ + +function match(req, routes, i) { + var captures + , method = req.method + , i = i || 0; + if ('HEAD' == method) method = 'GET'; + if (routes = routes[method]) { + var url = parse(req.url) + , pathname = url.pathname; + for (var len = routes.length; i < len; ++i) { + var route = routes[i] + , fn = route.fn + , path = route.path + , keys = fn.keys = route.keys; + if (captures = path.exec(pathname)) { + fn.method = method; + fn.params = []; + for (var j = 1, len = captures.length; j < len; ++j) { + var key = keys[j-1], + val = typeof captures[j] === 'string' + ? decodeURIComponent(captures[j]) + : captures[j]; + if (key) { + fn.params[key] = val; + } else { + fn.params.push(val); + } + } + req._route_index = i; + return fn; + } + } + } +} diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session.js new file mode 100644 index 0000000..7575cb6 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session.js @@ -0,0 +1,346 @@ + +/*! + * Connect - session + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Session = require('./session/session') + , MemoryStore = require('./session/memory') + , Cookie = require('./session/cookie') + , Store = require('./session/store') + , utils = require('./../utils') + , parse = require('url').parse + , crypto = require('crypto'); + +// environment + +var env = process.env.NODE_ENV; + +/** + * Expose the middleware. + */ + +exports = module.exports = session; + +/** + * Expose constructors. + */ + +exports.Store = Store; +exports.Cookie = Cookie; +exports.Session = Session; +exports.MemoryStore = MemoryStore; + +/** + * Warning message for `MemoryStore` usage in production. + */ + +var warning = 'Warning: connection.session() MemoryStore is not\n' + + 'designed for a production environment, as it will leak\n' + + 'memory, and obviously only work within a single process.'; + +/** + * Default finger-printing function. + */ + +function defaultFingerprint(req) { + var ua = req.headers['user-agent'] || ''; + return ua.replace(/;?\schromeframe\/[\d\.]+/, ''); +}; + +/** + * Paths to ignore, defaulting to `/favicon.ico`. + */ + +exports.ignore = ['/favicon.ico']; + +/** + * Setup session store with the given `options`. + * + * Session data is _not_ saved in the cookie itself, however + * cookies are used, so we must use the [cookieParser()](middleware-cookieParser.html) + * middleware _before_ `session()`. + * + * Examples: + * + * connect.createServer( + * connect.cookieParser() + * , connect.session({ secret: 'keyboard cat' }) + * ); + * + * Options: + * + * - `key` cookie name defaulting to `connect.sid` + * - `store` Session store instance + * - `fingerprint` Custom fingerprint generating function + * - `cookie` Session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: 14400000 }` + * - `secret` Secret string used to compute hash + * + * Ignore Paths: + * + * By default `/favicon.ico` is the only ignored path, all others + * will utilize sessions, to manipulate the paths ignored, use + * `connect.session.ignore.push('/my/path')`. This works for _full_ + * pathnames only, not segments nor substrings. + * + * connect.session.ignore.push('/robots.txt'); + * + * ## req.session + * + * To store or access session data, simply use the request property `req.session`, + * which is (generally) serialized as JSON by the store, so nested objects + * are typically fine. For example below is a user-specific view counter: + * + * connect( + * connect.cookieParser() + * , connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}) + * , connect.favicon() + * , function(req, res, next){ + * var sess = req.session; + * if (sess.views) { + * res.setHeader('Content-Type', 'text/html'); + * res.write('

    views: ' + sess.views + '

    '); + * res.write('

    expires in: ' + (sess.cookie.maxAge / 1000) + 's

    '); + * res.end(); + * sess.views++; + * } else { + * sess.views = 1; + * res.end('welcome to the session demo. refresh!'); + * } + * } + * ).listen(3000); + * + * ## Session#regenerate() + * + * To regenerate the session simply invoke the method, once complete + * a new SID and `Session` instance will be initialized at `req.session`. + * + * req.session.regenerate(function(err){ + * // will have a new session here + * }); + * + * ## Session#destroy() + * + * Destroys the session, removing `req.session`, will be re-generated next request. + * + * req.session.destroy(function(err){ + * // cannot access session here + * }); + * + * ## Session#reload() + * + * Reloads the session data. + * + * req.session.reload(function(err){ + * // session updated + * }); + * + * ## Session#save() + * + * Save the session. + * + * req.session.save(function(err){ + * // session saved + * }); + * + * ## Session#touch() + * + * Updates the `.maxAge`, and `.lastAccess` properties. Typically this is + * not necessary to call, as the session middleware does this for you. + * + * ## Session#cookie + * + * Each session has a unique cookie object accompany it. This allows + * you to alter the session cookie per visitor. For example we can + * set `req.session.cookie.expires` to `false` to enable the cookie + * to remain for only the duration of the user-agent. + * + * ## Session#maxAge + * + * Alternatively `req.session.cookie.maxAge` will return the time + * remaining in milliseconds, which we may also re-assign a new value + * to adjust the `.expires` property appropriately. The following + * are essentially equivalent + * + * var hour = 3600000; + * req.session.cookie.expires = new Date(Date.now() + hour); + * req.session.cookie.maxAge = hour; + * + * For example when `maxAge` is set to `60000` (one minute), and 30 seconds + * has elapsed it will return `30000` until the current request has completed, + * at which time `req.session.touch()` is called to update `req.session.lastAccess`, + * and reset `req.session.maxAge` to its original value. + * + * req.session.cookie.maxAge; + * // => 30000 + * + * Session Store Implementation: + * + * Every session store _must_ implement the following methods + * + * - `.get(sid, callback)` + * - `.set(sid, session, callback)` + * - `.destroy(sid, callback)` + * + * Recommended methods include, but are not limited to: + * + * - `.length(callback)` + * - `.clear(callback)` + * + * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +function session(options){ + var options = options || {} + , key = options.key || 'connect.sid' + , secret = options.secret + , store = options.store || new MemoryStore + , fingerprint = options.fingerprint || defaultFingerprint + , cookie = options.cookie; + + // notify user that this store is not + // meant for a production environment + if ('production' == env && store instanceof MemoryStore) { + console.warn(warning); + } + + // ensure secret is present + if (!secret) { + throw new Error('connect.session({ secret: "string" }) required for security'); + } + + // session hashing function + store.hash = function(req, base) { + return crypto + .createHmac('sha256', secret) + .update(base + fingerprint(req)) + .digest('base64') + .replace(/=*$/, ''); + }; + + // generates the new session + store.generate = function(req){ + var base = utils.uid(24); + var sessionID = base + '.' + store.hash(req, base); + req.sessionID = sessionID; + req.session = new Session(req); + req.session.cookie = new Cookie(cookie); + }; + + return function session(req, res, next) { + // self-awareness + if (req.session) return next(); + + // parse url + var url = parse(req.url) + , path = url.pathname; + + // ignorable paths + if (~exports.ignore.indexOf(path)) return next(); + + // expose store + req.sessionStore = store; + + // proxy writeHead() to Set-Cookie + var writeHead = res.writeHead; + res.writeHead = function(status, headers){ + if (req.session) { + var cookie = req.session.cookie; + // only send secure session cookies when there is a secure connection. + // proxySecure is a custom attribute to allow for a reverse proxy + // to handle SSL connections and to communicate to connect over HTTP that + // the incoming connection is secure. + var secured = cookie.secure && (req.connection.encrypted || req.connection.proxySecure); + if (secured || !cookie.secure) { + res.setHeader('Set-Cookie', cookie.serialize(key, req.sessionID)); + } + } + + res.writeHead = writeHead; + return res.writeHead(status, headers); + }; + + // proxy end() to commit the session + var end = res.end; + res.end = function(data, encoding){ + res.end = end; + if (req.session) { + // HACK: ensure Set-Cookie for implicit writeHead() + if (!res._header) res._implicitHeader(); + req.session.resetMaxAge(); + req.session.save(function(){ + res.end(data, encoding); + }); + } else { + res.end(data, encoding); + } + }; + + // session hashing + function hash(base) { + return store.hash(req, base); + } + + // generate the session + function generate() { + store.generate(req); + } + + // get the sessionID from the cookie + req.sessionID = req.cookies[key]; + + // make a new session if the browser doesn't send a sessionID + if (!req.sessionID) { + generate(); + next(); + return; + } + + // check the fingerprint + var parts = req.sessionID.split('.'); + if (parts[1] != hash(parts[0])) { + generate(); + next(); + return; + } + + // generate the session object + var pause = utils.pause(req); + store.get(req.sessionID, function(err, sess){ + // proxy to resume() events + var _next = next; + next = function(err){ + _next(err); + pause.resume(); + } + + // error handling + if (err) { + if ('ENOENT' == err.code) { + generate(); + next(); + } else { + next(err); + } + // no session + } else if (!sess) { + generate(); + next(); + // populate req.session + } else { + store.createSession(req, sess); + next(); + } + }); + }; +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js new file mode 100644 index 0000000..793c2e9 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js @@ -0,0 +1,126 @@ + +/*! + * Connect - session - Cookie + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../../utils'); + +/** + * Initialize a new `Cookie` with the given `options`. + * + * @param {Object} options + * @api private + */ + +var Cookie = module.exports = function Cookie(options) { + this.path = '/'; + this.httpOnly = true; + this.maxAge = 14400000; + if (options) utils.merge(this, options); + this.originalMaxAge = undefined == this.originalMaxAge + ? this.maxAge + : this.originalMaxAge; +}; + +/** + * Prototype. + */ + +Cookie.prototype = { + + /** + * Set expires `date`. + * + * @param {Date} date + * @api public + */ + + set expires(date) { + this._expires = date; + this.originalMaxAge = this.maxAge; + }, + + /** + * Get expires `date`. + * + * @return {Date} + * @api public + */ + + get expires() { + return this._expires; + }, + + /** + * Set expires via max-age in `ms`. + * + * @param {Number} ms + * @api public + */ + + set maxAge(ms) { + this.expires = 'number' == typeof ms + ? new Date(Date.now() + ms) + : ms; + }, + + /** + * Get expires max-age in `ms`. + * + * @return {Number} + * @api public + */ + + get maxAge() { + return this.expires instanceof Date + ? this.expires.valueOf() - Date.now() + : this.expires; + }, + + /** + * Return cookie data object. + * + * @return {Object} + * @api private + */ + + get data() { + return { + originalMaxAge: this.originalMaxAge + , expires: this._expires + , secure: this.secure + , httpOnly: this.httpOnly + , domain: this.domain + , path: this.path + } + }, + + /** + * Return a serialized cookie string. + * + * @return {String} + * @api public + */ + + serialize: function(name, val){ + return utils.serializeCookie(name, val, this.data); + }, + + /** + * Return JSON representation of this cookie. + * + * @return {Object} + * @api private + */ + + toJSON: function(){ + return this.data; + } +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/memory.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/memory.js new file mode 100644 index 0000000..ec569f5 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/memory.js @@ -0,0 +1,131 @@ + +/*! + * Connect - session - MemoryStore + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Store = require('./store') + , utils = require('../../utils') + , Session = require('./session'); + +/** + * Initialize a new `MemoryStore`. + * + * @api public + */ + +var MemoryStore = module.exports = function MemoryStore() { + this.sessions = {}; +}; + +/** + * Inherit from `Store.prototype`. + */ + +MemoryStore.prototype.__proto__ = Store.prototype; + +/** + * Attempt to fetch session by the given `sid`. + * + * @param {String} sid + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.get = function(sid, fn){ + var self = this; + process.nextTick(function(){ + var expires + , sess = self.sessions[sid]; + if (sess) { + sess = JSON.parse(sess); + expires = 'string' == typeof sess.cookie.expires + ? new Date(sess.cookie.expires) + : sess.cookie.expires; + if (!expires || new Date < expires) { + fn(null, sess); + } else { + self.destroy(sid, fn); + } + } else { + fn(); + } + }); +}; + +/** + * Commit the given `sess` object associated with the given `sid`. + * + * @param {String} sid + * @param {Session} sess + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.set = function(sid, sess, fn){ + var self = this; + process.nextTick(function(){ + self.sessions[sid] = JSON.stringify(sess); + fn && fn(); + }); +}; + +/** + * Destroy the session associated with the given `sid`. + * + * @param {String} sid + * @api public + */ + +MemoryStore.prototype.destroy = function(sid, fn){ + var self = this; + process.nextTick(function(){ + delete self.sessions[sid]; + fn && fn(); + }); +}; + +/** + * Invoke the given callback `fn` with all active sessions. + * + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.all = function(fn){ + var arr = [] + , keys = Object.keys(this.sessions); + for (var i = 0, len = keys.length; i < len; ++i) { + arr.push(this.sessions[keys[i]]); + } + fn(null, arr); +}; + +/** + * Clear all sessions. + * + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.clear = function(fn){ + this.sessions = {}; + fn && fn(); +}; + +/** + * Fetch number of sessions. + * + * @param {Function} fn + * @api public + */ + +MemoryStore.prototype.length = function(fn){ + fn(null, Object.keys(this.sessions).length); +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/session.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/session.js new file mode 100644 index 0000000..4e7e1a6 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/session.js @@ -0,0 +1,137 @@ + +/*! + * Connect - session - Session + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../../utils') + , Cookie = require('./cookie'); + +/** + * Create a new `Session` with the given request and `data`. + * + * @param {IncomingRequest} req + * @param {Object} data + * @api private + */ + +var Session = module.exports = function Session(req, data) { + Object.defineProperty(this, 'req', { value: req }); + Object.defineProperty(this, 'id', { value: req.sessionID }); + if ('object' == typeof data) { + utils.merge(this, data); + } else { + this.lastAccess = Date.now(); + } +}; + +/** + * Update `.lastAccess` timestamp, + * and reset `.cookie.maxAge` to prevent + * the cookie from expiring when the + * session is still active. + * + * @return {Session} for chaining + * @api public + */ + +Session.prototype.touch = function(){ + return this + .resetLastAccess() + .resetMaxAge(); +}; + +/** + * Update `.lastAccess` timestamp. + * + * @return {Session} for chaining + * @api public + */ + +Session.prototype.resetLastAccess = function(){ + this.lastAccess = Date.now(); + return this; +}; + +/** + * Reset `.maxAge` to `.originalMaxAge`. + * + * @return {Session} for chaining + * @api public + */ + +Session.prototype.resetMaxAge = function(){ + this.cookie.maxAge = this.cookie.originalMaxAge; + return this; +}; + +/** + * Save the session data with optional callback `fn(err)`. + * + * @param {Function} fn + * @return {Session} for chaining + * @api public + */ + +Session.prototype.save = function(fn){ + this.req.sessionStore.set(this.id, this, fn || function(){}); + return this; +}; + +/** + * Re-loads the session data _without_ altering + * the maxAge or lastAccess properties. Invokes the + * callback `fn(err)`, after which time if no exception + * has occurred the `req.session` property will be + * a new `Session` object, although representing the + * same session. + * + * @param {Function} fn + * @return {Session} for chaining + * @api public + */ + +Session.prototype.reload = function(fn){ + var req = this.req + , store = this.req.sessionStore; + store.get(this.id, function(err, sess){ + if (err) return fn(err); + if (!sess) return fn(new Error('failed to load session')); + store.createSession(req, sess); + fn(); + }); + return this; +}; + +/** + * Destroy `this` session. + * + * @param {Function} fn + * @return {Session} for chaining + * @api public + */ + +Session.prototype.destroy = function(fn){ + delete this.req.session; + this.req.sessionStore.destroy(this.id, fn); + return this; +}; + +/** + * Regenerate this request's session. + * + * @param {Function} fn + * @return {Session} for chaining + * @api public + */ + +Session.prototype.regenerate = function(fn){ + this.req.sessionStore.regenerate(this.req, fn); + return this; +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/store.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/store.js new file mode 100644 index 0000000..a71eeca --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/session/store.js @@ -0,0 +1,59 @@ + +/*! + * Connect - session - Store + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Session = require('./session') + , Cookie = require('./cookie') + , utils = require('../../utils'); + +/** + * Initialize abstract `Store`. + * + * @api private + */ + +var Store = module.exports = function Store(options){}; + +/** + * Re-generate the given requests's session. + * + * @param {IncomingRequest} req + * @return {Function} fn + * @api public + */ + +Store.prototype.regenerate = function(req, fn){ + var self = this; + this.destroy(req.sessionID, function(err){ + self.generate(req); + fn(err); + }); +}; + +/** + * Create session from JSON `sess` data. + * + * @param {IncomingRequest} req + * @param {Object} sess + * @return {Session} + * @api private + */ + +Store.prototype.createSession = function(req, sess){ + var expires = sess.cookie.expires + , orig = sess.cookie.originalMaxAge; + sess.cookie = new Cookie(sess.cookie); + if ('string' == typeof expires) sess.cookie.expires = new Date(expires); + sess.cookie.originalMaxAge = orig; + req.session = new Session(req, sess); + req.session.resetLastAccess(); + return req.session; +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/static.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/static.js new file mode 100644 index 0000000..0c99783 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/static.js @@ -0,0 +1,219 @@ + +/*! + * Connect - staticProvider + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , path = require('path') + , join = path.join + , basename = path.basename + , normalize = path.normalize + , utils = require('../utils') + , Buffer = require('buffer').Buffer + , parse = require('url').parse + , mime = require('mime'); + +/** + * Static file server with the given `root` path. + * + * Examples: + * + * var oneDay = 86400000; + * + * connect( + * connect.static(__dirname + '/public') + * ).listen(3000); + * + * connect( + * connect.static(__dirname + '/public', { maxAge: oneDay }) + * ).listen(3000); + * + * Options: + * + * - `maxAge` Browser cache maxAge in milliseconds. defaults to 0 + * - `hidden` Allow transfer of hidden files. defaults to false + * + * @param {String} root + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function static(root, options){ + options = options || {}; + + // root required + if (!root) throw new Error('static() root path required'); + options.root = root; + + return function static(req, res, next) { + options.path = req.url; + options.getOnly = true; + send(req, res, next, options); + }; +}; + +/** + * Expose mime module. + */ + +exports.mime = mime; + +/** + * Respond with 416 "Requested Range Not Satisfiable" + * + * @param {ServerResponse} res + * @api private + */ + +function invalidRange(res) { + var body = 'Requested Range Not Satisfiable'; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Length', body.length); + res.statusCode = 416; + res.end(body); +} + +/** + * Attempt to tranfer the requseted file to `res`. + * + * @param {ServerRequest} + * @param {ServerResponse} + * @param {Function} next + * @param {Object} options + * @api private + */ + +var send = exports.send = function(req, res, next, options){ + options = options || {}; + if (!options.path) throw new Error('path required'); + + // setup + var maxAge = options.maxAge || 0 + , ranges = req.headers.range + , head = 'HEAD' == req.method + , get = 'GET' == req.method + , root = options.root ? normalize(options.root) : null + , getOnly = options.getOnly + , fn = options.callback + , hidden = options.hidden + , done; + + // replace next() with callback when available + if (fn) next = fn; + + // ignore non-GET requests + if (getOnly && !get && !head) return next(); + + // parse url + var url = parse(options.path) + , path = decodeURIComponent(url.pathname) + , type; + + // null byte(s) + if (~path.indexOf('\0')) return utils.badRequest(res); + + // when root is not given, consider .. malicious + if (!root && ~path.indexOf('..')) return utils.forbidden(res); + + // join / normalize from optional root dir + path = normalize(join(root, path)); + + // malicious path + if (root && 0 != path.indexOf(root)) return fn + ? fn(new Error('Forbidden')) + : utils.forbidden(res); + + // index.html support + if ('/' == path[path.length - 1]) path += 'index.html'; + + // "hidden" file + if (!hidden && '.' == basename(path)[0]) return next(); + + fs.stat(path, function(err, stat){ + // mime type + type = mime.lookup(path); + + // ignore ENOENT + if (err) { + if (fn) return fn(err); + return 'ENOENT' == err.code + ? next() + : next(err); + // redirect directory in case index.html is present + } else if (stat.isDirectory()) { + res.statusCode = 301; + res.setHeader('Location', url.pathname + '/'); + res.end('Redirecting to ' + url.pathname + '/'); + return; + } + + var opts = {}; + + // we have a Range request + if (ranges) { + ranges = utils.parseRange(stat.size, ranges); + // valid + if (ranges) { + // TODO: stream options + // TODO: multiple support + opts.start = ranges[0].start; + opts.end = ranges[0].end; + res.statusCode = 206; + res.setHeader('Content-Range', 'bytes ' + + opts.start + + '-' + + opts.end + + '/' + + stat.size); + // invalid + } else { + return fn + ? fn(new Error('Requested Range Not Satisfiable')) + : invalidRange(res); + } + // stream the entire file + } else { + res.setHeader('Content-Length', stat.size); + if (!res.getHeader('Cache-Control')) res.setHeader('Cache-Control', 'public, max-age=' + (maxAge / 1000)); + if (!res.getHeader('Last-Modified')) res.setHeader('Last-Modified', stat.mtime.toUTCString()); + if (!res.getHeader('ETag')) res.setHeader('ETag', utils.etag(stat)); + + // conditional GET support + if (utils.conditionalGET(req)) { + if (!utils.modified(req, res)) { + return utils.notModified(res); + } + } + } + + // header fields + if (!res.getHeader('content-type')) { + var charset = mime.charsets.lookup(type); + res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : '')); + } + res.setHeader('Accept-Ranges', 'bytes'); + + // transfer + if (head) return res.end(); + + // stream + var stream = fs.createReadStream(path, opts); + stream.pipe(res); + + // callback + if (fn) { + function callback(err) { done || fn(err); done = true } + req.on('close', callback); + req.socket.on('error', callback); + stream.on('end', callback); + } + }); +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/vhost.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/vhost.js new file mode 100644 index 0000000..50be925 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/middleware/vhost.js @@ -0,0 +1,44 @@ + +/*! + * Connect - vhost + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Setup vhost for the given `hostname` and `server`. + * + * Examples: + * + * connect( + * connect.vhost('foo.com', + * connect.createServer(...middleware...) + * ), + * connect.vhost('bar.com', + * connect.createServer(...middleware...) + * ) + * ); + * + * @param {String} hostname + * @param {Server} server + * @return {Function} + * @api public + */ + +module.exports = function vhost(hostname, server){ + if (!hostname) throw new Error('vhost hostname required'); + if (!server) throw new Error('vhost server required'); + var regexp = new RegExp('^' + hostname.replace(/[*]/g, '(.*?)') + '$'); + if (server.onvhost) server.onvhost(hostname); + return function vhost(req, res, next){ + if (!req.headers.host) return next(); + var host = req.headers.host.split(':')[0]; + if (req.subdomains = regexp.exec(host)) { + req.subdomains = req.subdomains[0].split('.').slice(0, -1); + server.emit("request", req, res, next); + } else { + next(); + } + }; +}; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/patch.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/patch.js new file mode 100644 index 0000000..4c873bc --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/patch.js @@ -0,0 +1,67 @@ + +/*! + * Connect + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , res = http.OutgoingMessage.prototype; + +// original setHeader() + +var setHeader = res.setHeader; + +// original _renderHeaders() + +var _renderHeaders = res._renderHeaders; + +if (res._hasConnectPatch) return; + +/** + * Set header `field` to `val`, special-casing + * the `Set-Cookie` field for multiple support. + * + * @param {String} field + * @param {String} val + * @api public + */ + +res.setHeader = function(field, val){ + var key = field.toLowerCase() + , prev; + + // special-case Set-Cookie + if (this._headers && 'set-cookie' == key) { + if (prev = this.getHeader(field)) { + val = Array.isArray(prev) + ? prev.concat(val) + : [prev, val]; + } + // charset + } else if ('content-type' == key && this.charset) { + val += '; charset=' + this.charset; + } + + return setHeader.call(this, field, val); +}; + +/** + * Proxy `res.end()` to expose a 'header' event, + * allowing arbitrary augmentation before the header + * fields are written to the socket. + * + * NOTE: this _only_ supports node's progressive header + * field API aka `res.setHeader()`. + */ + +res._renderHeaders = function(){ + this.emit('header'); + return _renderHeaders.call(this); +}; + +res._hasConnectPatch = true; diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/directory.html b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/directory.html new file mode 100644 index 0000000..15164bb --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/directory.html @@ -0,0 +1,75 @@ + + + listing directory {directory} + + + + + +
    +

    {linked-path}

    + {files} +
    + + \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/error.html b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/error.html new file mode 100644 index 0000000..34e0df5 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/error.html @@ -0,0 +1,13 @@ + + + {error} + + + +
    +

    {title}

    +

    500 {error}

    +
      {stack}
    +
    + + \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/favicon.ico b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/favicon.ico new file mode 100644 index 0000000..895fc96 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/favicon.ico differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page.png new file mode 100755 index 0000000..03ddd79 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_add.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_add.png new file mode 100755 index 0000000..d5bfa07 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_add.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png new file mode 100755 index 0000000..89ee2da Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_code.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_code.png new file mode 100755 index 0000000..f7ea904 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_code.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png new file mode 100755 index 0000000..195dc6d Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png new file mode 100755 index 0000000..3141467 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png new file mode 100755 index 0000000..046811e Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_error.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_error.png new file mode 100755 index 0000000..f07f449 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_error.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png new file mode 100755 index 0000000..eb6158e Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_find.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_find.png new file mode 100755 index 0000000..2f19388 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_find.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png new file mode 100755 index 0000000..8e83281 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_go.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_go.png new file mode 100755 index 0000000..80fe1ed Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_go.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_green.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_green.png new file mode 100755 index 0000000..de8e003 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_green.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_key.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_key.png new file mode 100755 index 0000000..d6626cb Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_key.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png new file mode 100755 index 0000000..7e56870 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_link.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_link.png new file mode 100755 index 0000000..312eab0 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_link.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png new file mode 100755 index 0000000..246a2f0 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png new file mode 100755 index 0000000..968f073 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_red.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_red.png new file mode 100755 index 0000000..0b18247 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_red.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png new file mode 100755 index 0000000..cf347c7 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_save.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_save.png new file mode 100755 index 0000000..caea546 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_save.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white.png new file mode 100755 index 0000000..8b8b1ca Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png new file mode 100755 index 0000000..8f8095e Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png new file mode 100755 index 0000000..159b240 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png new file mode 100755 index 0000000..aa23dde Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png new file mode 100755 index 0000000..34a05cc Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png new file mode 100755 index 0000000..f501a59 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png new file mode 100755 index 0000000..848bdaf Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png new file mode 100755 index 0000000..0c76bd1 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png new file mode 100755 index 0000000..87a6914 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png new file mode 100755 index 0000000..c66011f Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png new file mode 100755 index 0000000..2b6b100 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png new file mode 100755 index 0000000..a9f31a2 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png new file mode 100755 index 0000000..a87cf84 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png new file mode 100755 index 0000000..ffb8fc9 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png new file mode 100755 index 0000000..0a7d6f4 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png new file mode 100755 index 0000000..bddba1f Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png new file mode 100755 index 0000000..af1ecaf Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png new file mode 100755 index 0000000..4cc537a Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png new file mode 100755 index 0000000..b93e776 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png new file mode 100755 index 0000000..9fc5a0a Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png new file mode 100755 index 0000000..b977d7e Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png new file mode 100755 index 0000000..5818436 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png new file mode 100755 index 0000000..5769120 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png new file mode 100755 index 0000000..8d719df Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png new file mode 100755 index 0000000..106f5aa Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png new file mode 100755 index 0000000..e4a1ecb Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png new file mode 100755 index 0000000..7e62a92 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png new file mode 100755 index 0000000..e902abb Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png new file mode 100755 index 0000000..1d2d0a4 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png new file mode 100755 index 0000000..d616484 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png new file mode 100755 index 0000000..7215d1e Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png new file mode 100755 index 0000000..bf7bd1c Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png new file mode 100755 index 0000000..f6b74cc Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png new file mode 100755 index 0000000..d3fffb6 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png new file mode 100755 index 0000000..a65bcb3 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png new file mode 100755 index 0000000..23a37b8 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png new file mode 100755 index 0000000..f907e44 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png new file mode 100755 index 0000000..5b2cbb3 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png new file mode 100755 index 0000000..7868a25 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png new file mode 100755 index 0000000..134b669 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png new file mode 100755 index 0000000..c4eff03 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png new file mode 100755 index 0000000..884ffd6 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png new file mode 100755 index 0000000..f59b7c4 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png new file mode 100755 index 0000000..44084ad Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png new file mode 100755 index 0000000..3a1441c Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png new file mode 100755 index 0000000..e770829 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png new file mode 100755 index 0000000..813f712 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png new file mode 100755 index 0000000..d9cf132 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png new file mode 100755 index 0000000..52699bf Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png new file mode 100755 index 0000000..4a05955 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png new file mode 100755 index 0000000..a0a433d Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png new file mode 100755 index 0000000..1eb8809 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png new file mode 100755 index 0000000..ae8ecbf Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png new file mode 100755 index 0000000..6ed2490 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png new file mode 100755 index 0000000..fecadd0 Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png new file mode 100755 index 0000000..fd4bbcc Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_word.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_word.png new file mode 100755 index 0000000..834cdfa Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_word.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_world.png b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_world.png new file mode 100755 index 0000000..b8895dd Binary files /dev/null and b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/icons/page_world.png differ diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/public/style.css b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/style.css new file mode 100644 index 0000000..32b6507 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/public/style.css @@ -0,0 +1,141 @@ +body { + margin: 0; + padding: 80px 100px; + font: 13px "Helvetica Neue", "Lucida Grande", "Arial"; + background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9)); + background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9); + background-repeat: no-repeat; + color: #555; + -webkit-font-smoothing: antialiased; +} +h1, h2, h3 { + margin: 0; + font-size: 22px; + color: #343434; +} +h1 em, h2 em { + padding: 0 5px; + font-weight: normal; +} +h1 { + font-size: 60px; +} +h2 { + margin-top: 10px; +} +h3 { + margin: 5px 0 10px 0; + padding-bottom: 5px; + border-bottom: 1px solid #eee; + font-size: 18px; +} +ul { + margin: 0; + padding: 0; +} +ul li { + margin: 5px 0; + padding: 3px 8px; + list-style: none; +} +ul li:hover { + cursor: pointer; + color: #2e2e2e; +} +ul li .path { + padding-left: 5px; + font-weight: bold; +} +ul li .line { + padding-right: 5px; + font-style: italic; +} +ul li:first-child .path { + padding-left: 0; +} +p { + line-height: 1.5; +} +a { + color: #555; + text-decoration: none; +} +a:hover { + color: #303030; +} +#stacktrace { + margin-top: 15px; +} +.directory h1 { + margin-bottom: 15px; + font-size: 18px; +} +ul#files { + width: 100%; + height: 500px; +} +ul#files li { + padding: 0; +} +ul#files li img { + position: absolute; + top: 5px; + left: 5px; +} +ul#files li a { + position: relative; + display: block; + margin: 1px; + width: 30%; + height: 25px; + line-height: 25px; + text-indent: 8px; + float: left; + border: 1px solid transparent; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + overflow: hidden; + text-overflow: ellipsis; +} +ul#files li a.icon { + text-indent: 25px; +} +ul#files li a:focus, +ul#files li a:hover { + outline: none; + background: rgba(255,255,255,0.65); + border: 1px solid #ececec; +} +ul#files li a.highlight { + -webkit-transition: background .4s ease-in-out; + background: #ffff4f; + border-color: #E9DC51; +} +#search { + display: block; + position: fixed; + top: 20px; + right: 20px; + width: 90px; + -webkit-transition: width ease 0.2s, opacity ease 0.4s; + -moz-transition: width ease 0.2s, opacity ease 0.4s; + -webkit-border-radius: 32px; + -moz-border-radius: 32px; + -webkit-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03); + -moz-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03); + -webkit-font-smoothing: antialiased; + text-align: left; + font: 13px "Helvetica Neue", Arial, sans-serif; + padding: 4px 10px; + border: none; + background: transparent; + margin-bottom: 0; + outline: none; + opacity: 0.7; + color: #888; +} +#search:focus { + width: 120px; + opacity: 1.0; +} diff --git a/NodeDrawing/node_modules/express/node_modules/connect/lib/utils.js b/NodeDrawing/node_modules/express/node_modules/connect/lib/utils.js new file mode 100644 index 0000000..feca712 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/lib/utils.js @@ -0,0 +1,427 @@ + +/*! + * Connect - utils + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , Path = require('path') + , fs = require('fs'); + +/** + * Flatten the given `arr`. + * + * @param {Array} arr + * @return {Array} + * @api private + */ + +exports.flatten = function(arr, ret){ + var ret = ret || [] + , len = arr.length; + for (var i = 0; i < len; ++i) { + if (Array.isArray(arr[i])) { + exports.flatten(arr[i], ret); + } else { + ret.push(arr[i]); + } + } + return ret; +}; + +/** + * Return md5 hash of the given string and optional encoding, + * defaulting to hex. + * + * utils.md5('wahoo'); + * // => "e493298061761236c96b02ea6aa8a2ad" + * + * @param {String} str + * @param {String} encoding + * @return {String} + * @api public + */ + +exports.md5 = function(str, encoding){ + return crypto + .createHash('md5') + .update(str) + .digest(encoding || 'hex'); +}; + +/** + * Merge object b with object a. + * + * var a = { foo: 'bar' } + * , b = { bar: 'baz' }; + * + * utils.merge(a, b); + * // => { foo: 'bar', bar: 'baz' } + * + * @param {Object} a + * @param {Object} b + * @return {Object} + * @api public + */ + +exports.merge = function(a, b){ + if (a && b) { + for (var key in b) { + a[key] = b[key]; + } + } + return a; +}; + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api public + */ + +exports.escape = function(html){ + return String(html) + .replace(/&(?!\w+;)/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; + + +/** + * Return a unique identifier with the given `len`. + * + * utils.uid(10); + * // => "FDaS435D2z" + * + * @param {Number} len + * @return {String} + * @api public + */ + +exports.uid = function(len) { + var buf = [] + , chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + , charlen = chars.length; + + for (var i = 0; i < len; ++i) { + buf.push(chars[getRandomInt(0, charlen - 1)]); + } + + return buf.join(''); +}; + +/** + * Parse the given cookie string into an object. + * + * @param {String} str + * @return {Object} + * @api public + */ + +exports.parseCookie = function(str){ + var obj = {} + , pairs = str.split(/[;,] */); + for (var i = 0, len = pairs.length; i < len; ++i) { + var pair = pairs[i] + , eqlIndex = pair.indexOf('=') + , key = pair.substr(0, eqlIndex).trim().toLowerCase() + , val = pair.substr(++eqlIndex, pair.length).trim(); + + // quoted values + if ('"' == val[0]) val = val.slice(1, -1); + + // only assign once + if (undefined == obj[key]) { + val = val.replace(/\+/g, ' '); + try { + obj[key] = decodeURIComponent(val); + } catch (err) { + if (err instanceof URIError) { + obj[key] = val; + } else { + throw err; + } + } + } + } + return obj; +}; + +/** + * Serialize the given object into a cookie string. + * + * utils.serializeCookie('name', 'tj', { httpOnly: true }) + * // => "name=tj; httpOnly" + * + * @param {String} name + * @param {String} val + * @param {Object} obj + * @return {String} + * @api public + */ + +exports.serializeCookie = function(name, val, obj){ + var pairs = [name + '=' + encodeURIComponent(val)] + , obj = obj || {}; + + if (obj.domain) pairs.push('domain=' + obj.domain); + if (obj.path) pairs.push('path=' + obj.path); + if (obj.expires) pairs.push('expires=' + obj.expires.toUTCString()); + if (obj.httpOnly) pairs.push('httpOnly'); + if (obj.secure) pairs.push('secure'); + + return pairs.join('; '); +}; + +/** + * Pause `data` and `end` events on the given `obj`. + * Middleware performing async tasks _should_ utilize + * this utility (or similar), to re-emit data once + * the async operation has completed, otherwise these + * events may be lost. + * + * var pause = utils.pause(req); + * fs.readFile(path, function(){ + * next(); + * pause.resume(); + * }); + * + * @param {Object} obj + * @return {Object} + * @api public + */ + +exports.pause = function(obj){ + var onData + , onEnd + , events = []; + + // buffer data + obj.on('data', onData = function(data, encoding){ + events.push(['data', data, encoding]); + }); + + // buffer end + obj.on('end', onEnd = function(data, encoding){ + events.push(['end', data, encoding]); + }); + + return { + end: function(){ + obj.removeListener('data', onData); + obj.removeListener('end', onEnd); + }, + resume: function(){ + this.end(); + for (var i = 0, len = events.length; i < len; ++i) { + obj.emit.apply(obj, events[i]); + } + } + }; +}; + +/** + * Check `req` and `res` to see if it has been modified. + * + * @param {IncomingMessage} req + * @param {ServerResponse} res + * @return {Boolean} + * @api public + */ + +exports.modified = function(req, res, headers) { + var headers = headers || res._headers || {} + , modifiedSince = req.headers['if-modified-since'] + , lastModified = headers['last-modified'] + , noneMatch = req.headers['if-none-match'] + , etag = headers['etag']; + + if (noneMatch) noneMatch = noneMatch.split(/ *, */); + + // check If-None-Match + if (noneMatch && etag && ~noneMatch.indexOf(etag)) { + return false; + } + + // check If-Modified-Since + if (modifiedSince && lastModified) { + modifiedSince = new Date(modifiedSince); + lastModified = new Date(lastModified); + // Ignore invalid dates + if (!isNaN(modifiedSince.getTime())) { + if (lastModified <= modifiedSince) return false; + } + } + + return true; +}; + +/** + * Strip `Content-*` headers from `res`. + * + * @param {ServerResponse} res + * @api public + */ + +exports.removeContentHeaders = function(res){ + Object.keys(res._headers).forEach(function(field){ + if (0 == field.indexOf('content')) { + res.removeHeader(field); + } + }); +}; + +/** + * Check if `req` is a conditional GET request. + * + * @param {IncomingMessage} req + * @return {Boolean} + * @api public + */ + +exports.conditionalGET = function(req) { + return req.headers['if-modified-since'] + || req.headers['if-none-match']; +}; + +/** + * Respond with 403 "Forbidden". + * + * @param {ServerResponse} res + * @api public + */ + +exports.forbidden = function(res) { + var body = 'Forbidden'; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Length', body.length); + res.statusCode = 403; + res.end(body); +}; + +/** + * Respond with 401 "Unauthorized". + * + * @param {ServerResponse} res + * @param {String} realm + * @api public + */ + +exports.unauthorized = function(res, realm) { + res.statusCode = 401; + res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"'); + res.end('Unauthorized'); +}; + +/** + * Respond with 400 "Bad Request". + * + * @param {ServerResponse} res + * @api public + */ + +exports.badRequest = function(res) { + res.statusCode = 400; + res.end('Bad Request'); +}; + +/** + * Respond with 304 "Not Modified". + * + * @param {ServerResponse} res + * @param {Object} headers + * @api public + */ + +exports.notModified = function(res) { + exports.removeContentHeaders(res); + res.statusCode = 304; + res.end(); +}; + +/** + * Return an ETag in the form of `"-"` + * from the given `stat`. + * + * @param {Object} stat + * @return {String} + * @api public + */ + +exports.etag = function(stat) { + return '"' + stat.size + '-' + Number(stat.mtime) + '"'; +}; + +/** + * Parse "Range" header `str` relative to the given file `size`. + * + * @param {Number} size + * @param {String} str + * @return {Array} + * @api public + */ + +exports.parseRange = function(size, str){ + var valid = true; + var arr = str.substr(6).split(',').map(function(range){ + var range = range.split('-') + , start = parseInt(range[0], 10) + , end = parseInt(range[1], 10); + + // -500 + if (isNaN(start)) { + start = size - end; + end = size - 1; + // 500- + } else if (isNaN(end)) { + end = size - 1; + } + + // Invalid + if (isNaN(start) || isNaN(end) || start > end) valid = false; + + return { start: start, end: end }; + }); + return valid ? arr : undefined; +}; + +/** + * Convert array-like object to an `Array`. + * + * node-bench measured "16.5 times faster than Array.prototype.slice.call()" + * + * @param {Object} obj + * @return {Array} + * @api public + */ + +var toArray = exports.toArray = function(obj){ + var len = obj.length + , arr = new Array(len); + for (var i = 0; i < len; ++i) { + arr[i] = obj[i]; + } + return arr; +}; + +/** + * Retrun a random int, used by `utils.uid()` + * + * @param {Number} min + * @param {Number} max + * @return {Number} + * @api private + */ + +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} diff --git a/NodeDrawing/node_modules/express/node_modules/connect/meta.json b/NodeDrawing/node_modules/express/node_modules/connect/meta.json new file mode 100644 index 0000000..1461506 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/meta.json @@ -0,0 +1 @@ +{"files":["lib/connect.js","lib/http.js","lib/https.js","lib/index.js","lib/middleware/basicAuth.js","lib/middleware/bodyParser.js","lib/middleware/compiler.js","lib/middleware/cookieParser.js","lib/middleware/directory.js","lib/middleware/errorHandler.js","lib/middleware/favicon.js","lib/middleware/limit.js","lib/middleware/logger.js","lib/middleware/methodOverride.js","lib/middleware/profiler.js","lib/middleware/responseTime.js","lib/middleware/router.js","lib/middleware/session/cookie.js","lib/middleware/session/memory.js","lib/middleware/session/session.js","lib/middleware/session/store.js","lib/middleware/session.js","lib/middleware/static.js","lib/middleware/vhost.js","lib/patch.js","lib/utils.js"]} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/package.json b/NodeDrawing/node_modules/express/node_modules/connect/package.json new file mode 100644 index 0000000..0b11b5f --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/package.json @@ -0,0 +1,24 @@ +{ + "name": "connect", + "version": "1.6.2", + "description": "High performance middleware framework", + "keywords": ["framework", "web", "middleware", "connect", "rack"], + "repository": "git://github.com/senchalabs/connect.git", + "author": "TJ Holowaychuk (http://tjholowaychuk.com)", + "repository": "git://github.com/senchalabs/connect", + "dependencies": { + "qs": ">= 0.3.0", + "mime": ">= 0.0.1" + }, + "devDependencies": { + "expresso": "0.7.6", + "koala": "0.1.2", + "less": "1.1.1", + "sass": "0.5.0", + "markdown": "0.2.1", + "ejs": "0.4.3", + "should": "0.2.1" + }, + "main": "index", + "engines": { "node": ">= 0.4.1 < 0.5.0" } +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/connect/test.js b/NodeDrawing/node_modules/express/node_modules/connect/test.js new file mode 100644 index 0000000..90c79fa --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/connect/test.js @@ -0,0 +1,65 @@ + +/** + * Module dependencies. + */ + +var connect = require('./') + , http = require('http') + , fs = require('fs'); + +// connect() +// .use(connect.logger(':req[accept] -> :res[content-type]')) +// .use(connect.favicon()) +// .use('/connect', connect.static(__dirname + '/lib')) +// .use('/connect', connect.directory(__dirname + '/lib')) +// .use(function(req, res, next){ +// var body = 'OK'; +// res.setHeader('Content-Length', body.length); +// res.end(body); +// }) +// .listen(3000); + + +// http.createServer(connect() +// .use(connect.favicon()) +// .use(connect.cookieParser()) +// .use(connect.session({ secret: 'test' })) +// .use(function(req, res, next){ +// console.log(req.header); +// res.end('hey\n'); +// }) +// ).listen(3000); + +// TODO: make sure it's nice to use within handler + +// http.createServer(connect() +// .use(connect.favicon()) +// .use(connect.logger({ immediate: true, format: ':method :url' })) +// .use(function(req, res, next){ +// setTimeout(next, 5000); +// }) +// ).listen(3000); + +// var app = connect() +// .use(connect.favicon()) +// .use(function(req, res){ +// res.end('Hello\n'); +// }); + +// TODO: cache + +// ab -n 5000 -c 50 -k http://local/Readme.md +// connect: 2665 +// node-static: 5425 + +// connect() +// .use(connect.static(__dirname)) +// .listen(3000); + +var static = require('node-static') + , file = new static.Server(__dirname); + +var send = connect.static(__dirname); +http.createServer(function(req, res){ + file.serve(req, res); +}).listen(3000); \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/mime/LICENSE b/NodeDrawing/node_modules/express/node_modules/mime/LICENSE new file mode 100644 index 0000000..451fc45 --- /dev/null +++ b/NodeDrawing/node_modules/express/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/NodeDrawing/node_modules/express/node_modules/mime/README.md b/NodeDrawing/node_modules/express/node_modules/mime/README.md new file mode 100644 index 0000000..5aa6a28 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/mime/README.md @@ -0,0 +1,54 @@ +# mime + +Support for mapping between file extensions and MIME types. This module uses the latest version of the Apache "mime.types" file (maps over 620 types to 800+ extensions). It is also trivially easy to add your own types and extensions, should you need to do that. + +## Install + +Install with [npm](http://github.com/isaacs/npm): + + npm install mime + +## API + +### mime.lookup(path) - lookup the type for a file or extension + + 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) - lookup 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.) + +## "Can you add support for [some type/extension]?" + +Start by adding support for the type in your project using the mime.define() or mime.load() methods (documented below). + +If there's a type that is shared across node.js modules, by different people, create an issue here and we'll add it if it makes sense. + +If the type in question applies to projects outside the node.js community (e.g. if [IANA](http://www.iana.org/assignments/media-types/) approves a new type) file a [bug with Apache](http://httpd.apache.org/bug_report.html) and create an issue here that links to it. + +### 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' + mime.extension('text/x-some-format'); // => 'x-sf' + +### mime.load(filepath) - Load mappings from an Apache ".types" format file + + mime.load('./my_project.types'); diff --git a/NodeDrawing/node_modules/express/node_modules/mime/index.js b/NodeDrawing/node_modules/express/node_modules/mime/index.js new file mode 100644 index 0000000..4a58dae --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/mime/index.js @@ -0,0 +1 @@ +module.exports = require('./mime'); diff --git a/NodeDrawing/node_modules/express/node_modules/mime/mime.js b/NodeDrawing/node_modules/express/node_modules/mime/mime.js new file mode 100644 index 0000000..62bff98 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/mime/mime.js @@ -0,0 +1,89 @@ +var path = require('path'), + fs = require('fs'); + +var mime = module.exports = { + /** Map of extension to mime type */ + types: {}, + + /** Map of mime type to extension */ + extensions :{}, + + /** + * 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 + */ + define: function(map) { + for (var type in map) { + var exts = map[type]; + + for (var i = 0; i < exts.length; i++) { + mime.types[exts[i]] = type; + } + + mime.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. + */ + load: function(file) { + // Read file and split into lines + var map = {}, + content = fs.readFileSync(file, 'ascii'), + lines = content.split(/[\r\n]+/); + + lines.forEach(function(line, lineno) { + // Clean up whitespace/comments, and split into fields + var fields = line.replace(/\s*#.*|^\s*|\s*$/g, '').split(/\s+/); + map[fields.shift()] = fields; + }); + + mime.define(map); + }, + + /** + * Lookup a mime type based on extension + */ + lookup: function(path, fallback) { + var ext = path.replace(/.*[\.\/]/, '').toLowerCase(); + return mime.types[ext] || fallback || mime.default_type; + }, + + /** + * Return file extension associated with a mime type + */ + extension: function(mimeType) { + return mime.extensions[mimeType]; + }, + + /** + * Lookup a charset based on mime type. + */ + charsets: { + lookup: function (mimeType, fallback) { + // Assume text types are utf8. Modify mime logic as needed. + return /^text\//.test(mimeType) ? 'UTF-8' : fallback; + } + } +}; + +// Load our local copy of +// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types +mime.load(path.join(__dirname, 'mime.types')); + +// Overlay enhancements we've had requests for (and that seem to make sense) +mime.load(path.join(__dirname, 'node.types')); + +// Set the default type +mime.default_type = mime.types.bin; diff --git a/NodeDrawing/node_modules/express/node_modules/mime/mime.types b/NodeDrawing/node_modules/express/node_modules/mime/mime.types new file mode 100644 index 0000000..6a90929 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/mime/mime.types @@ -0,0 +1,1479 @@ +# 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 . +# +# 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/cals-1840 +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/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/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/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/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/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 lha lrf lzh so iso dmg dist distz pkg bpk dump elc deploy +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/onenote onetoc onetoc2 onetmp onepkg +# 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/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/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/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.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.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.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.car car +application/vnd.curl.pcurl pcurl +# application/vnd.cybank +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.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.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.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+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 x3d +# 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.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.packageitem+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-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-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-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.ncd.control +# application/vnd.ncd.reference +# application/vnd.nervana +# application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +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.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-pcc+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.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.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.route66.link66+xml link66 +# 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.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.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.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-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-bzip bz +application/x-bzip2 bz2 boz +application/x-cdlink vcd +application/x-chat chat +application/x-chess-pgn pgn +# application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +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-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-futuresplash spl +application/x-gnumeric gnumeric +application/x-gtar gtar +# application/x-gzip +application/x-hdf hdf +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-mobipocket-ebook prc mobi +application/x-ms-application application +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 +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-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-stuffit sit +application/x-stuffitx sitx +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo texi +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x-xfig fig +application/x-xpinstall xpi +# application/x400-bp +# 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/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/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/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/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/ogg oga ogg spx +# 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/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.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-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-wav wav +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/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.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-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fhc fh4 fh5 fh7 +image/x-icon ico +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-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 +# 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/calendar ics ifb +text/css css +text/csv csv +# text/directory +# text/dns +# text/ecmascript +# text/enriched +# text/example +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/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.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-pascal p pas +text/x-java-source java +text/x-setext etx +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.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-ms-asf asf asx +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 +x-conference/x-cooltalk ice diff --git a/NodeDrawing/node_modules/express/node_modules/mime/node.types b/NodeDrawing/node_modules/express/node_modules/mime/node.types new file mode 100644 index 0000000..a2cb85f --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/mime/node.types @@ -0,0 +1,7 @@ +application/mp4 m4p +application/octet-stream bin buffer +audio/mp4 m4a +text/cache-manifest appcache manifest +application/x-web-app-manifest+json webapp +application/x-mpegURL m3u8 +video/MP2T ts diff --git a/NodeDrawing/node_modules/express/node_modules/mime/package.json b/NodeDrawing/node_modules/express/node_modules/mime/package.json new file mode 100644 index 0000000..436e699 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/mime/package.json @@ -0,0 +1,11 @@ +{ "name" : "mime" +, "description" : "A comprehensive library for mime-type mapping" +, "url" : "http://github.com/bentomas/node-mime" +, "keywords" : ["util", "mime"] +, "author" : "Benjamin Thomas " +, "contributors" : [] +, "dependencies" : [] +, "lib" : "." +, "main" : "mime.js" +, "version" : "1.2.2" +} diff --git a/NodeDrawing/node_modules/express/node_modules/mime/test.js b/NodeDrawing/node_modules/express/node_modules/mime/test.js new file mode 100644 index 0000000..44ce43f --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/mime/test.js @@ -0,0 +1,74 @@ +var mime = require('./mime'); +exports["test mime lookup"] = function(test) { + // easy + test.equal('text/plain', mime.lookup('text.txt')); + + // hidden file or multiple periods + test.equal('text/plain', mime.lookup('.text.txt')); + + // just an extension + test.equal('text/plain', mime.lookup('.txt')); + + // just an extension without a dot + test.equal('text/plain', mime.lookup('txt')); + + // default + test.equal('application/octet-stream', mime.lookup('text.nope')); + + // fallback + test.equal('fallback', mime.lookup('text.fallback', 'fallback')); + + test.finish(); +}; + +exports["test extension lookup"] = function(test) { + // easy + test.equal('txt', mime.extension(mime.types.text)); + test.equal('html', mime.extension(mime.types.htm)); + test.equal('bin', mime.extension('application/octet-stream')); + + test.finish(); +}; + +exports["test mime lookup uppercase"] = function(test) { + // easy + test.equal('text/plain', mime.lookup('TEXT.TXT')); + + // just an extension + test.equal('text/plain', mime.lookup('.TXT')); + + // just an extension without a dot + test.equal('text/plain', mime.lookup('TXT')); + + // default + test.equal('application/octet-stream', mime.lookup('TEXT.NOPE')); + + // fallback + test.equal('fallback', mime.lookup('TEXT.FALLBACK', 'fallback')); + + test.finish(); +}; + +exports["test custom types"] = function(test) { + test.equal('application/octet-stream', mime.lookup('file.buffer')); + test.equal('audio/mp4', mime.lookup('file.m4a')); + + test.finish(); +}; + +exports["test charset lookup"] = function(test) { + // easy + test.equal('UTF-8', mime.charsets.lookup('text/plain')); + + // none + test.ok(typeof mime.charsets.lookup(mime.types.js) == 'undefined'); + + // fallback + test.equal('fallback', mime.charsets.lookup('application/octet-stream', 'fallback')); + + test.finish(); +}; + +if (module == require.main) { + require('async_testing').run(__filename, process.ARGV); +} diff --git a/NodeDrawing/node_modules/express/node_modules/qs/.gitmodules b/NodeDrawing/node_modules/express/node_modules/qs/.gitmodules new file mode 100644 index 0000000..49e31da --- /dev/null +++ b/NodeDrawing/node_modules/express/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/NodeDrawing/node_modules/express/node_modules/qs/History.md b/NodeDrawing/node_modules/express/node_modules/qs/History.md new file mode 100644 index 0000000..e327c0b --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/History.md @@ -0,0 +1,52 @@ + +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 \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/Makefile b/NodeDrawing/node_modules/express/node_modules/qs/Makefile new file mode 100644 index 0000000..4bbe969 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/Makefile @@ -0,0 +1,7 @@ + +test: + @./support/expresso/bin/expresso \ + -I support \ + -I lib + +.PHONY: test \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/Readme.md b/NodeDrawing/node_modules/express/node_modules/qs/Readme.md new file mode 100644 index 0000000..3d1d584 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/Readme.md @@ -0,0 +1,49 @@ +# node-querystring + + query string parser for node 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 + + require('qs').parse('user[name][first]=tj&user[email]=tj'); + // => { user: { name: { first: 'tj' }, email: 'tj' } } + +## Testing + +Update git submodules: + + $ git submodule init + $ git submodule update + +and execute: + + $ make test + +## 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/NodeDrawing/node_modules/express/node_modules/qs/benchmark.js b/NodeDrawing/node_modules/express/node_modules/qs/benchmark.js new file mode 100644 index 0000000..97e2c93 --- /dev/null +++ b/NodeDrawing/node_modules/express/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/NodeDrawing/node_modules/express/node_modules/qs/examples.js b/NodeDrawing/node_modules/express/node_modules/qs/examples.js new file mode 100644 index 0000000..9b652b0 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/examples.js @@ -0,0 +1,48 @@ + +/** + * 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) diff --git a/NodeDrawing/node_modules/express/node_modules/qs/index.js b/NodeDrawing/node_modules/express/node_modules/qs/index.js new file mode 100644 index 0000000..d177d20 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/querystring'); \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/lib/querystring.js b/NodeDrawing/node_modules/express/node_modules/qs/lib/querystring.js new file mode 100644 index 0000000..4246e96 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/lib/querystring.js @@ -0,0 +1,236 @@ +/*! + * querystring + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Library version. + */ + +exports.version = '0.3.1'; + +/** + * Object#toString() ref for stringify(). + */ + +var toString = Object.prototype.toString; + +/** + * Cache non-integer test regexp. + */ + +var notint = /[^0-9]/; + +/** + * Parse the given query `str`, returning an object. + * + * @param {String} str + * @return {Object} + * @api public + */ + +exports.parse = function(str){ + if (null == str || '' == str) return {}; + + 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; + } + + 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) + , parent = ret; + + // ?foo + if ('' == key) key = pair, val = ''; + + // nested + if (~key.indexOf(']')) { + var parts = key.split('[') + , len = parts.length + , last = len - 1; + + function parse(parts, parent, key) { + 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 { + 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(notint.test(part) && Array.isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part); + // key + } else { + if(notint.test(part) && Array.isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part); + } + } + } + + parse(parts, parent, 'base'); + // optimize + } else { + if (notint.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 ret; + }, {base: {}}).base; +}; + +/** + * 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; + } +}; + +/** + * 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 + '[]')); + } + 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/NodeDrawing/node_modules/express/node_modules/qs/package.json b/NodeDrawing/node_modules/express/node_modules/qs/package.json new file mode 100644 index 0000000..98a406d --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/package.json @@ -0,0 +1,9 @@ +{ + "name": "qs", + "description": "querystring parser", + "version": "0.3.1", + "repository": {}, + "author": "TJ Holowaychuk (http://tjholowaychuk.com)", + "main": "index", + "engines": { "node": "*" } +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/.gitignore b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/.gitignore new file mode 100644 index 0000000..432563f --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +lib-cov +*.seed \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/.gitmodules b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/.gitmodules new file mode 100644 index 0000000..191ddeb --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/jscoverage"] + path = deps/jscoverage + url = git://github.com/visionmedia/node-jscoverage.git diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/History.md b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/History.md new file mode 100644 index 0000000..cb16fa9 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/History.md @@ -0,0 +1,128 @@ + +0.7.2 / 2010-12-29 +================== + + * Fixed problem with `listen()` sometimes firing on the same tick [guillermo] + +0.7.1 / 2010-12-28 +================== + + * Fixed `assert.request()` client logic into an issue() function, fired upon the `listen()` callback if the server doesn't have an assigned fd. [guillermo] + * Removed `--watch` + +0.7.0 / 2010-11-19 +================== + + * Removed `assert` from test function signature + Just use `require('assert')` :) this will make integration + with libraries like [should](http://github.com/visionmedia/should) cleaner. + +0.6.4 / 2010-11-02 +================== + + * Added regexp support to `assert.response()` headers + * Removed `waitForExit` code, causing issues + +0.6.3 / 2010-11-02 +================== + + * Added `assert.response()` body RegExp support + * Fixed issue with _--serial_ not executing files sequentially. Closes #42 + * Fixed hang when modules use `setInterval` - monitor running tests & force the process to quit after all have completed + timeout [Steve Mason] + +0.6.2 / 2010-09-17 +================== + + * Added _node-jsocoverage_ to package.json (aka will respect npm's binroot) + * Added _-t, --timeout_ MS option, defaulting to 2000 ms + * Added _-s, --serial_ + * __PREFIX__ clobberable + * Fixed `assert.response()` for latest node + * Fixed cov reporting from exploding on empty files + +0.6.2 / 2010-08-03 +================== + + * Added `assert.type()` + * Renamed `assert.isNotUndefined()` to `assert.isDefined()` + * Fixed `assert.includes()` param ordering + +0.6.0 / 2010-07-31 +================== + + * Added _docs/api.html_ + * Added -w, --watch + * Added `Array` support to `assert.includes()` + * Added; outputting exceptions immediately. Closes #19 + * Fixed `assert.includes()` param ordering + * Fixed `assert.length()` param ordering + * Fixed jscoverage links + +0.5.0 / 2010-07-16 +================== + + * Added support for async exports + * Added timeout support to `assert.response()`. Closes #3 + * Added 4th arg callback support to `assert.response()` + * Added `assert.length()` + * Added `assert.match()` + * Added `assert.isUndefined()` + * Added `assert.isNull()` + * Added `assert.includes()` + * Added growlnotify support via -g, --growl + * Added -o, --only TESTS. Ex: --only "test foo()" --only "test foo(), test bar()" + * Removed profanity + +0.4.0 / 2010-07-09 +================== + + * Added reporting source coverage (respects --boring for color haters) + * Added callback to assert.response(). Closes #12 + * Fixed; putting exceptions to stderr. Closes #13 + +0.3.1 / 2010-06-28 +================== + + * Faster assert.response() + +0.3.0 / 2010-06-28 +================== + + * Added -p, --port NUM flags + * Added assert.response(). Closes #11 + +0.2.1 / 2010-06-25 +================== + + * Fixed issue with reporting object assertions + +0.2.0 / 2010-06-21 +================== + + * Added `make uninstall` + * Added better readdir() failure message + * Fixed `make install` for kiwi + +0.1.0 / 2010-06-15 +================== + + * Added better usage docs via --help + * Added better conditional color support + * Added pre exit assertion support + +0.0.3 / 2010-06-02 +================== + + * Added more room for filenames in test coverage + * Added boring output support via --boring (suppress colored output) + * Fixed async failure exit status + +0.0.2 / 2010-05-30 +================== + + * Fixed exit status for CI support + +0.0.1 / 2010-05-30 +================== + + * Initial release \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/Makefile b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/Makefile new file mode 100644 index 0000000..8acfe56 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/Makefile @@ -0,0 +1,53 @@ + +PREFIX ?= /usr/local +BIN = bin/expresso +JSCOV = deps/jscoverage/node-jscoverage +DOCS = docs/index.md +HTMLDOCS = $(DOCS:.md=.html) + +test: $(BIN) + @./$(BIN) -I lib --growl $(TEST_FLAGS) test/*.test.js + +test-cov: + @./$(BIN) -I lib --cov $(TEST_FLAGS) test/*.test.js + +test-serial: + @./$(BIN) --serial -I lib $(TEST_FLAGS) test/serial/*.test.js + +install: install-jscov install-expresso + +uninstall: + rm -f $(PREFIX)/bin/expresso + rm -f $(PREFIX)/bin/node-jscoverage + +install-jscov: $(JSCOV) + install $(JSCOV) $(PREFIX)/bin + +install-expresso: + install $(BIN) $(PREFIX)/bin + +$(JSCOV): + cd deps/jscoverage && ./configure && make && mv jscoverage node-jscoverage + +clean: + @cd deps/jscoverage && git clean -fd + +docs: docs/api.html $(HTMLDOCS) + +%.html: %.md + @echo "... $< > $@" + @ronn -5 --pipe --fragment $< \ + | cat docs/layout/head.html - docs/layout/foot.html \ + > $@ + +docs/api.html: bin/expresso + dox \ + --title "Expresso" \ + --ribbon "http://github.com/visionmedia/expresso" \ + --desc "Insanely fast TDD framework for [node](http://nodejs.org) featuring code coverage reporting." \ + $< > $@ + +docclean: + rm -f docs/*.html + +.PHONY: test test-cov install uninstall install-expresso install-jscov clean docs docclean \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/Readme.md b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/Readme.md new file mode 100644 index 0000000..05c972e --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/Readme.md @@ -0,0 +1,61 @@ + +# Expresso + + TDD framework for [nodejs](http://nodejs.org). + +## Features + + - light-weight + - intuitive async support + - intuitive test runner executable + - test coverage support and reporting + - uses the _assert_ module + - `assert.eql()` alias of `assert.deepEqual()` + - `assert.response()` http response utility + - `assert.includes()` + - `assert.type()` + - `assert.isNull()` + - `assert.isUndefined()` + - `assert.isNotNull()` + - `assert.isDefined()` + - `assert.match()` + - `assert.length()` + +## Installation + +To install both expresso _and_ node-jscoverage run: + + $ make install + +To install expresso alone (no build required) run: + + $ make install-expresso + +Install via npm: + + $ npm install expresso + +## 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. diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/bin/expresso b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/bin/expresso new file mode 100755 index 0000000..ec1edc8 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/bin/expresso @@ -0,0 +1,856 @@ +#!/usr/bin/env node + +/* + * Expresso + * Copyright(c) TJ Holowaychuk + * (MIT Licensed) + */ + +/** + * Module dependencies. + */ + +var assert = require('assert'), + childProcess = require('child_process'), + http = require('http'), + path = require('path'), + sys = require('sys'), + cwd = process.cwd(), + fs = require('fs'), + defer; + +/** + * Expresso version. + */ + +var version = '0.7.2'; + +/** + * Failure count. + */ + +var failures = 0; + + +/** + * Number of tests executed. + */ + +var testcount = 0; + +/** + * Whitelist of tests to run. + */ + +var only = []; + +/** + * Boring output. + */ + +var boring = false; + +/** + * Growl notifications. + */ + +var growl = false; + +/** + * Server port. + */ + +var port = 5555; + +/** + * Execute serially. + */ + +var serial = false; + +/** + * Default timeout. + */ + +var timeout = 2000; + +/** + * Quiet output. + */ + +var quiet = false; + +/** + * Usage documentation. + */ + +var usage = '' + + '[bold]{Usage}: expresso [options] ' + + '\n' + + '\n[bold]{Options}:' + + '\n -g, --growl Enable growl notifications' + + '\n -c, --coverage Generate and report test coverage' + + '\n -q, --quiet Suppress coverage report if 100%' + + '\n -t, --timeout MS Timeout in milliseconds, defaults to 2000' + + '\n -r, --require PATH Require the given module path' + + '\n -o, --only TESTS Execute only the comma sperated TESTS (can be set several times)' + + '\n -I, --include PATH Unshift the given path to require.paths' + + '\n -p, --port NUM Port number for test servers, starts at 5555' + + '\n -s, --serial Execute tests serially' + + '\n -b, --boring Suppress ansi-escape colors' + + '\n -v, --version Output version number' + + '\n -h, --help Display help information' + + '\n'; + +// Parse arguments + +var files = [], + args = process.argv.slice(2); + +while (args.length) { + var arg = args.shift(); + switch (arg) { + case '-h': + case '--help': + print(usage + '\n'); + process.exit(1); + break; + case '-v': + case '--version': + sys.puts(version); + process.exit(1); + break; + case '-i': + case '-I': + case '--include': + if (arg = args.shift()) { + require.paths.unshift(arg); + } else { + throw new Error('--include requires a path'); + } + break; + case '-o': + case '--only': + if (arg = args.shift()) { + only = only.concat(arg.split(/ *, */)); + } else { + throw new Error('--only requires comma-separated test names'); + } + break; + case '-p': + case '--port': + if (arg = args.shift()) { + port = parseInt(arg, 10); + } else { + throw new Error('--port requires a number'); + } + break; + case '-r': + case '--require': + if (arg = args.shift()) { + require(arg); + } else { + throw new Error('--require requires a path'); + } + break; + case '-t': + case '--timeout': + if (arg = args.shift()) { + timeout = parseInt(arg, 10); + } else { + throw new Error('--timeout requires an argument'); + } + break; + case '-c': + case '--cov': + case '--coverage': + defer = true; + childProcess.exec('rm -fr lib-cov && node-jscoverage lib lib-cov', function(err){ + if (err) throw err; + require.paths.unshift('lib-cov'); + run(files); + }) + break; + case '-q': + case '--quiet': + quiet = true; + break; + case '-b': + case '--boring': + boring = true; + break; + case '-g': + case '--growl': + growl = true; + break; + case '-s': + case '--serial': + serial = true; + break; + default: + if (/\.js$/.test(arg)) { + files.push(arg); + } + break; + } +} + +/** + * Colorized sys.error(). + * + * @param {String} str + */ + +function print(str){ + sys.error(colorize(str)); +} + +/** + * Colorize the given string using ansi-escape sequences. + * Disabled when --boring is set. + * + * @param {String} str + * @return {String} + */ + +function colorize(str){ + var colors = { bold: 1, red: 31, green: 32, yellow: 33 }; + return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str){ + return boring + ? str + : '\x1B[' + colors[color] + 'm' + str + '\x1B[0m'; + }); +} + +// Alias deepEqual as eql for complex equality + +assert.eql = assert.deepEqual; + +/** + * Assert that `val` is null. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isNull = function(val, msg) { + assert.strictEqual(null, val, msg); +}; + +/** + * Assert that `val` is not null. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isNotNull = function(val, msg) { + assert.notStrictEqual(null, val, msg); +}; + +/** + * Assert that `val` is undefined. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isUndefined = function(val, msg) { + assert.strictEqual(undefined, val, msg); +}; + +/** + * Assert that `val` is not undefined. + * + * @param {Mixed} val + * @param {String} msg + */ + +assert.isDefined = function(val, msg) { + assert.notStrictEqual(undefined, val, msg); +}; + +/** + * Assert that `obj` is `type`. + * + * @param {Mixed} obj + * @param {String} type + * @api public + */ + +assert.type = function(obj, type, msg){ + var real = typeof obj; + msg = msg || 'typeof ' + sys.inspect(obj) + ' is ' + real + ', expected ' + type; + assert.ok(type === real, msg); +}; + +/** + * Assert that `str` matches `regexp`. + * + * @param {String} str + * @param {RegExp} regexp + * @param {String} msg + */ + +assert.match = function(str, regexp, msg) { + msg = msg || sys.inspect(str) + ' does not match ' + sys.inspect(regexp); + assert.ok(regexp.test(str), msg); +}; + +/** + * Assert that `val` is within `obj`. + * + * Examples: + * + * assert.includes('foobar', 'bar'); + * assert.includes(['foo', 'bar'], 'foo'); + * + * @param {String|Array} obj + * @param {Mixed} val + * @param {String} msg + */ + +assert.includes = function(obj, val, msg) { + msg = msg || sys.inspect(obj) + ' does not include ' + sys.inspect(val); + assert.ok(obj.indexOf(val) >= 0, msg); +}; + +/** + * Assert length of `val` is `n`. + * + * @param {Mixed} val + * @param {Number} n + * @param {String} msg + */ + +assert.length = function(val, n, msg) { + msg = msg || sys.inspect(val) + ' has length of ' + val.length + ', expected ' + n; + assert.equal(n, val.length, msg); +}; + +/** + * Assert response from `server` with + * the given `req` object and `res` assertions object. + * + * @param {Server} server + * @param {Object} req + * @param {Object|Function} res + * @param {String} msg + */ + +assert.response = function(server, req, res, msg){ + // Check that the server is ready or defer + if (!server.fd) { + if (!('__deferred' in server)) { + server.__deferred = []; + } + server.__deferred.push(arguments); + if (!server.__started) { + server.listen(server.__port = port++, '127.0.0.1', function(){ + if (server.__deferred) { + process.nextTick(function(){ + server.__deferred.forEach(function(args){ + assert.response.apply(assert, args); + }); + }); + } + }); + server.__started = true; + } + return; + } + + // Callback as third or fourth arg + var callback = typeof res === 'function' + ? res + : typeof msg === 'function' + ? msg + : function(){}; + + // Default messate to test title + if (typeof msg === 'function') msg = null; + msg = msg || assert.testTitle; + msg += '. '; + + // Pending responses + server.__pending = server.__pending || 0; + server.__pending++; + + // Create client + if (!server.fd) { + server.listen(server.__port = port++, '127.0.0.1', issue); + } else { + issue(); + } + + function issue(){ + if (!server.client) + server.client = http.createClient(server.__port); + + // Issue request + var timer, + client = server.client, + method = req.method || 'GET', + status = res.status || res.statusCode, + data = req.data || req.body, + requestTimeout = req.timeout || 0; + + var request = client.request(method, req.url, req.headers); + + // Timeout + if (requestTimeout) { + timer = setTimeout(function(){ + --server.__pending || server.close(); + delete req.timeout; + assert.fail(msg + 'Request timed out after ' + requestTimeout + 'ms.'); + }, requestTimeout); + } + + if (data) request.write(data); + request.on('response', function(response){ + response.body = ''; + response.setEncoding('utf8'); + response.on('data', function(chunk){ response.body += chunk; }); + response.on('end', function(){ + --server.__pending || server.close(); + if (timer) clearTimeout(timer); + + // Assert response body + if (res.body !== undefined) { + var eql = res.body instanceof RegExp + ? res.body.test(response.body) + : res.body === response.body; + assert.ok( + eql, + msg + 'Invalid response body.\n' + + ' Expected: ' + sys.inspect(res.body) + '\n' + + ' Got: ' + sys.inspect(response.body) + ); + } + + // Assert response status + if (typeof status === 'number') { + assert.equal( + response.statusCode, + status, + msg + colorize('Invalid response status code.\n' + + ' Expected: [green]{' + status + '}\n' + + ' Got: [red]{' + response.statusCode + '}') + ); + } + + // Assert response headers + if (res.headers) { + var keys = Object.keys(res.headers); + for (var i = 0, len = keys.length; i < len; ++i) { + var name = keys[i], + actual = response.headers[name.toLowerCase()], + expected = res.headers[name], + eql = expected instanceof RegExp + ? expected.test(actual) + : expected == actual; + assert.ok( + eql, + msg + colorize('Invalid response header [bold]{' + name + '}.\n' + + ' Expected: [green]{' + expected + '}\n' + + ' Got: [red]{' + actual + '}') + ); + } + } + + // Callback + callback(response); + }); + }); + request.end(); + } +}; + +/** + * Pad the given string to the maximum width provided. + * + * @param {String} str + * @param {Number} width + * @return {String} + */ + +function lpad(str, width) { + str = String(str); + var n = width - str.length; + if (n < 1) return str; + while (n--) str = ' ' + str; + return str; +} + +/** + * Pad the given string to the maximum width provided. + * + * @param {String} str + * @param {Number} width + * @return {String} + */ + +function rpad(str, width) { + str = String(str); + var n = width - str.length; + if (n < 1) return str; + while (n--) str = str + ' '; + return str; +} + +/** + * Report test coverage. + * + * @param {Object} cov + */ + +function reportCoverage(cov) { + // Stats + print('\n [bold]{Test Coverage}\n'); + var sep = ' +------------------------------------------+----------+------+------+--------+', + lastSep = ' +----------+------+------+--------+'; + sys.puts(sep); + sys.puts(' | filename | coverage | LOC | SLOC | missed |'); + sys.puts(sep); + for (var name in cov) { + var file = cov[name]; + if (Array.isArray(file)) { + sys.print(' | ' + rpad(name, 40)); + sys.print(' | ' + lpad(file.coverage.toFixed(2), 8)); + sys.print(' | ' + lpad(file.LOC, 4)); + sys.print(' | ' + lpad(file.SLOC, 4)); + sys.print(' | ' + lpad(file.totalMisses, 6)); + sys.print(' |\n'); + } + } + sys.puts(sep); + sys.print(' ' + rpad('', 40)); + sys.print(' | ' + lpad(cov.coverage.toFixed(2), 8)); + sys.print(' | ' + lpad(cov.LOC, 4)); + sys.print(' | ' + lpad(cov.SLOC, 4)); + sys.print(' | ' + lpad(cov.totalMisses, 6)); + sys.print(' |\n'); + sys.puts(lastSep); + // Source + for (var name in cov) { + if (name.match(/\.js$/)) { + var file = cov[name]; + if ((file.coverage < 100) || !quiet) { + print('\n [bold]{' + name + '}:'); + print(file.source); + sys.print('\n'); + } + } + } +} + +/** + * Populate code coverage data. + * + * @param {Object} cov + */ + +function populateCoverage(cov) { + cov.LOC = + cov.SLOC = + cov.totalFiles = + cov.totalHits = + cov.totalMisses = + cov.coverage = 0; + for (var name in cov) { + var file = cov[name]; + if (Array.isArray(file)) { + // Stats + ++cov.totalFiles; + cov.totalHits += file.totalHits = coverage(file, true); + cov.totalMisses += file.totalMisses = coverage(file, false); + file.totalLines = file.totalHits + file.totalMisses; + cov.SLOC += file.SLOC = file.totalLines; + if (!file.source) file.source = []; + cov.LOC += file.LOC = file.source.length; + file.coverage = (file.totalHits / file.totalLines) * 100; + // Source + var width = file.source.length.toString().length; + file.source = file.source.map(function(line, i){ + ++i; + var hits = file[i] === 0 ? 0 : (file[i] || ' '); + if (!boring) { + if (hits === 0) { + hits = '\x1b[31m' + hits + '\x1b[0m'; + line = '\x1b[41m' + line + '\x1b[0m'; + } else { + hits = '\x1b[32m' + hits + '\x1b[0m'; + } + } + return '\n ' + lpad(i, width) + ' | ' + hits + ' | ' + line; + }).join(''); + } + } + cov.coverage = (cov.totalHits / cov.SLOC) * 100; +} + +/** + * Total coverage for the given file data. + * + * @param {Array} data + * @return {Type} + */ + +function coverage(data, val) { + var n = 0; + for (var i = 0, len = data.length; i < len; ++i) { + if (data[i] !== undefined && data[i] == val) ++n; + } + return n; +} + +/** + * Test if all files have 100% coverage + * + * @param {Object} cov + * @return {Boolean} + */ + +function hasFullCoverage(cov) { + for (var name in cov) { + var file = cov[name]; + if (file instanceof Array) { + if (file.coverage !== 100) { + return false; + } + } + } + return true; +} + +/** + * Run the given test `files`, or try _test/*_. + * + * @param {Array} files + */ + +function run(files) { + cursor(false); + if (!files.length) { + try { + files = fs.readdirSync('test').map(function(file){ + return 'test/' + file; + }); + } catch (err) { + print('\n failed to load tests in [bold]{./test}\n'); + ++failures; + process.exit(1); + } + } + runFiles(files); +} + +/** + * Show the cursor when `show` is true, otherwise hide it. + * + * @param {Boolean} show + */ + +function cursor(show) { + if (show) { + sys.print('\x1b[?25h'); + } else { + sys.print('\x1b[?25l'); + } +} + +/** + * Run the given test `files`. + * + * @param {Array} files + */ + +function runFiles(files) { + if (serial) { + (function next(){ + if (files.length) { + runFile(files.shift(), next); + } + })(); + } else { + files.forEach(runFile); + } +} + +/** + * Run tests for the given `file`, callback `fn()` when finished. + * + * @param {String} file + * @param {Function} fn + */ + +function runFile(file, fn) { + if (file.match(/\.js$/)) { + var title = path.basename(file), + file = path.join(cwd, file), + mod = require(file.replace(/\.js$/, '')); + (function check(){ + var len = Object.keys(mod).length; + if (len) { + runSuite(title, mod, fn); + } else { + setTimeout(check, 20); + } + })(); + } +} + +/** + * Report `err` for the given `test` and `suite`. + * + * @param {String} suite + * @param {String} test + * @param {Error} err + */ + +function error(suite, test, err) { + ++failures; + var name = err.name, + stack = err.stack ? err.stack.replace(err.name, '') : '', + label = test === 'uncaught' + ? test + : suite + ' ' + test; + print('\n [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n'); +} + +/** + * Run the given tests, callback `fn()` when finished. + * + * @param {String} title + * @param {Object} tests + * @param {Function} fn + */ + +var dots = 0; +function runSuite(title, tests, fn) { + // Keys + var keys = only.length + ? only.slice(0) + : Object.keys(tests); + + // Setup + var setup = tests.setup || function(fn){ fn(); }; + + // Iterate tests + (function next(){ + if (keys.length) { + var key, + test = tests[key = keys.shift()]; + // Non-tests + if (key === 'setup') return next(); + + // Run test + if (test) { + try { + ++testcount; + assert.testTitle = key; + if (serial) { + sys.print('.'); + if (++dots % 25 === 0) sys.print('\n'); + setup(function(){ + if (test.length < 1) { + test(); + next(); + } else { + var id = setTimeout(function(){ + throw new Error("'" + key + "' timed out"); + }, timeout); + test(function(){ + clearTimeout(id); + next(); + }); + } + }); + } else { + test(function(fn){ + process.on('beforeExit', function(){ + try { + fn(); + } catch (err) { + error(title, key, err); + } + }); + }); + } + } catch (err) { + error(title, key, err); + } + } + if (!serial) next(); + } else if (serial) { + fn(); + } + })(); +} + +/** + * Report exceptions. + */ + +function report() { + cursor(true); + process.emit('beforeExit'); + if (failures) { + print('\n [bold]{Failures}: [red]{' + failures + '}\n\n'); + notify('Failures: ' + failures); + } else { + if (serial) print(''); + print('\n [green]{100%} ' + testcount + ' tests\n'); + notify('100% ok'); + } + if (typeof _$jscoverage === 'object') { + populateCoverage(_$jscoverage); + if (!hasFullCoverage(_$jscoverage) || !quiet) { + reportCoverage(_$jscoverage); + } + } +} + +/** + * Growl notify the given `msg`. + * + * @param {String} msg + */ + +function notify(msg) { + if (growl) { + childProcess.exec('growlnotify -name Expresso -m "' + msg + '"'); + } +} + +// Report uncaught exceptions + +process.on('uncaughtException', function(err){ + error('uncaught', 'uncaught', err); +}); + +// Show cursor + +['INT', 'TERM', 'QUIT'].forEach(function(sig){ + process.on('SIG' + sig, function(){ + cursor(true); + process.exit(1); + }); +}); + +// Report test coverage when available +// and emit "beforeExit" event to perform +// final assertions + +var orig = process.emit; +process.emit = function(event){ + if (event === 'exit') { + report(); + process.reallyExit(failures); + } + orig.apply(this, arguments); +}; + +// Run test files + +if (!defer) run(files); diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/api.html b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/api.html new file mode 100644 index 0000000..7b8fb2b --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/api.html @@ -0,0 +1,1080 @@ +Fork me on GitHub + + Expresso + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Expresso

    Insanely fast TDD framework for node featuring code coverage reporting.

    expresso

    bin/expresso
    +

    !/usr/bin/env node

    +
    +
    
    + * Expresso
    + * Copyright(c) TJ Holowaychuk &lt;tj@vision-media.ca&gt;
    + * (MIT Licensed)
    + 
    +
    +

    Module dependencies. +

    +
    +
    var assert = require('assert'),
    +    childProcess = require('child_process'),
    +    http = require('http'),
    +    path = require('path'),
    +    sys = require('sys'),
    +    cwd = process.cwd(),
    +    fs = require('fs'),
    +    defer;
    +
    +

    Expresso version. +

    +
    +
    var version = '0.6.4';
    +
    +

    Failure count. +

    +
    +
    var failures = 0;
    +
    +

    Number of tests executed. +

    +
    +
    var testcount = 0;
    +
    +

    Whitelist of tests to run. +

    +
    +
    var only = [];
    +
    +

    Boring output. +

    +
    +
    var boring = false;
    +
    +

    Growl notifications. +

    +
    +
    var growl = false;
    +
    +

    Server port. +

    +
    +
    var port = 5555;
    +
    +

    Watch mode. +

    +
    +
    var watch = false;
    +
    +

    Execute serially. +

    +
    +
    var serial = false;
    +
    +

    Default timeout. +

    +
    +
    var timeout = 2000;
    +
    +

    Usage documentation. +

    +
    +
    var usage = ''
    +    + '[bold]{Usage}: expresso [options] <file ...>'
    +    + '\n'
    +    + '\n[bold]{Options}:'
    +    + '\n  -w, --watch          Watch for modifications and re-execute tests'
    +    + '\n  -g, --growl          Enable growl notifications'
    +    + '\n  -c, --coverage       Generate and report test coverage'
    +    + '\n  -t, --timeout MS     Timeout in milliseconds, defaults to 2000'
    +    + '\n  -r, --require PATH   Require the given module path'
    +    + '\n  -o, --only TESTS     Execute only the comma sperated TESTS (can be set several times)'
    +    + '\n  -I, --include PATH   Unshift the given path to require.paths'
    +    + '\n  -p, --port NUM       Port number for test servers, starts at 5555'
    +    + '\n  -s, --serial         Execute tests serially'
    +    + '\n  -b, --boring         Suppress ansi-escape colors'
    +    + '\n  -v, --version        Output version number'
    +    + '\n  -h, --help           Display help information'
    +    + '\n';
    +
    +// Parse arguments
    +
    +var files = [],
    +    args = process.argv.slice(2);
    +
    +while (args.length) {
    +    var arg = args.shift();
    +    switch (arg) {
    +        case '-h':
    +        case '--help':
    +            print(usage + '\n');
    +            process.exit(1);
    +            break;
    +        case '-v':
    +        case '--version':
    +            sys.puts(version);
    +            process.exit(1);
    +            break;
    +        case '-i':
    +        case '-I':
    +        case '--include':
    +            if (arg = args.shift()) {
    +                require.paths.unshift(arg);
    +            } else {
    +                throw new Error('--include requires a path');
    +            }
    +            break;
    +        case '-o':
    +        case '--only':
    +            if (arg = args.shift()) {
    +                only = only.concat(arg.split(/ *, */));
    +            } else {
    +                throw new Error('--only requires comma-separated test names');
    +            }
    +            break;
    +        case '-p':
    +        case '--port':
    +            if (arg = args.shift()) {
    +                port = parseInt(arg, 10);
    +            } else {
    +                throw new Error('--port requires a number');
    +            }
    +            break;
    +        case '-r':
    +        case '--require':
    +            if (arg = args.shift()) {
    +                require(arg);
    +            } else {
    +                throw new Error('--require requires a path');
    +            }
    +            break;
    +        case '-t':
    +        case '--timeout':
    +          if (arg = args.shift()) {
    +            timeout = parseInt(arg, 10);
    +          } else {
    +            throw new Error('--timeout requires an argument');
    +          }
    +          break;
    +        case '-c':
    +        case '--cov':
    +        case '--coverage':
    +            defer = true;
    +            childProcess.exec('rm -fr lib-cov && node-jscoverage lib lib-cov', function(err){
    +                if (err) throw err;
    +                require.paths.unshift('lib-cov');
    +                run(files);
    +            })
    +            break;
    +        case '-b':
    +        case '--boring':
    +        	boring = true;
    +        	break;
    +        case '-w':
    +        case '--watch':
    +            watch = true;
    +            break;
    +        case '-g':
    +        case '--growl':
    +            growl = true;
    +            break;
    +        case '-s':
    +        case '--serial':
    +            serial = true;
    +            break;
    +        default:
    +            if (/\.js$/.test(arg)) {
    +                files.push(arg);
    +            }
    +            break;
    +    }
    +}
    +
    +

    Colorized sys.error().

    + +

    + +
    • param: String str

    +
    +
    function print(str){
    +    sys.error(colorize(str));
    +}
    +
    +

    Colorize the given string using ansi-escape sequences. +Disabled when --boring is set.

    + +

    + +
    • param: String str

    • return: String

    +
    +
    function colorize(str){
    +    var colors = { bold: 1, red: 31, green: 32, yellow: 33 };
    +    return str.replace(/\[(\w+)\]\{([^]*?)\}/g, function(_, color, str){
    +        return boring
    +            ? str
    +            : '\x1B[' + colors[color] + 'm' + str + '\x1B[0m';
    +    });
    +}
    +
    +// Alias deepEqual as eql for complex equality
    +
    +assert.eql = assert.deepEqual;
    +
    +

    Assert that val is null.

    + +

    + +
    • param: Mixed val

    • param: String msg

    +
    +
    assert.isNull = function(val, msg) {
    +    assert.strictEqual(null, val, msg);
    +};
    +
    +

    Assert that val is not null.

    + +

    + +
    • param: Mixed val

    • param: String msg

    +
    +
    assert.isNotNull = function(val, msg) {
    +    assert.notStrictEqual(null, val, msg);
    +};
    +
    +

    Assert that val is undefined.

    + +

    + +
    • param: Mixed val

    • param: String msg

    +
    +
    assert.isUndefined = function(val, msg) {
    +    assert.strictEqual(undefined, val, msg);
    +};
    +
    +

    Assert that val is not undefined.

    + +

    + +
    • param: Mixed val

    • param: String msg

    +
    +
    assert.isDefined = function(val, msg) {
    +    assert.notStrictEqual(undefined, val, msg);
    +};
    +
    +

    Assert that obj is type.

    + +

    + +
    • param: Mixed obj

    • param: String type

    • api: public

    +
    +
    assert.type = function(obj, type, msg){
    +    var real = typeof obj;
    +    msg = msg || 'typeof ' + sys.inspect(obj) + ' is ' + real + ', expected ' + type;
    +    assert.ok(type === real, msg);
    +};
    +
    +

    Assert that str matches regexp.

    + +

    + +
    • param: String str

    • param: RegExp regexp

    • param: String msg

    +
    +
    assert.match = function(str, regexp, msg) {
    +    msg = msg || sys.inspect(str) + ' does not match ' + sys.inspect(regexp);
    +    assert.ok(regexp.test(str), msg);
    +};
    +
    +

    Assert that val is within obj.

    + +

    Examples

    + +

    assert.includes('foobar', 'bar'); + assert.includes(['foo', 'bar'], 'foo');

    + +

    + +
    • param: String | Array obj

    • param: Mixed val

    • param: String msg

    +
    +
    assert.includes = function(obj, val, msg) {
    +    msg = msg || sys.inspect(obj) + ' does not include ' + sys.inspect(val);
    +    assert.ok(obj.indexOf(val) &gt;= 0, msg);
    +};
    +
    +

    Assert length of val is n.

    + +

    + +
    • param: Mixed val

    • param: Number n

    • param: String msg

    +
    +
    assert.length = function(val, n, msg) {
    +    msg = msg || sys.inspect(val) + ' has length of ' + val.length + ', expected ' + n;
    +    assert.equal(n, val.length, msg);
    +};
    +
    +

    Assert response from server with +the given req object and res assertions object.

    + +

    + +
    • param: Server server

    • param: Object req

    • param: Object | Function res

    • param: String msg

    +
    +
    assert.response = function(server, req, res, msg){
    +    // Callback as third or fourth arg
    +    var callback = typeof res === 'function'
    +        ? res
    +        : typeof msg === 'function'
    +            ? msg
    +            : function(){};
    +
    +    // Default messate to test title
    +    if (typeof msg === 'function') msg = null;
    +    msg = msg || assert.testTitle;
    +    msg += '. ';
    +
    +    // Pending responses
    +    server.__pending = server.__pending || 0;
    +    server.__pending++;
    +
    +    // Create client
    +    if (!server.fd) {
    +        server.listen(server.__port = port++, '127.0.0.1');
    +        server.client = http.createClient(server.__port);
    +    }
    +
    +    // Issue request
    +    var timer,
    +        client = server.client,
    +        method = req.method || 'GET',
    +        status = res.status || res.statusCode,
    +        data = req.data || req.body,
    +        requestTimeout = req.timeout || 0;
    +
    +    var request = client.request(method, req.url, req.headers);
    +
    +    // Timeout
    +    if (requestTimeout) {
    +        timer = setTimeout(function(){
    +            --server.__pending || server.close();
    +            delete req.timeout;
    +            assert.fail(msg + 'Request timed out after ' + requestTimeout + 'ms.');
    +        }, requestTimeout);
    +    }
    +
    +    if (data) request.write(data);
    +    request.addListener('response', function(response){
    +        response.body = '';
    +        response.setEncoding('utf8');
    +        response.addListener('data', function(chunk){ response.body += chunk; });
    +        response.addListener('end', function(){
    +            --server.__pending || server.close();
    +            if (timer) clearTimeout(timer);
    +
    +            // Assert response body
    +            if (res.body !== undefined) {
    +                var eql = res.body instanceof RegExp
    +                  ? res.body.test(response.body)
    +                  : res.body === response.body;
    +                assert.ok(
    +                    eql,
    +                    msg + 'Invalid response body.\n'
    +                        + '    Expected: ' + sys.inspect(res.body) + '\n'
    +                        + '    Got: ' + sys.inspect(response.body)
    +                );
    +            }
    +
    +            // Assert response status
    +            if (typeof status === 'number') {
    +                assert.equal(
    +                    response.statusCode,
    +                    status,
    +                    msg + colorize('Invalid response status code.\n'
    +                        + '    Expected: [green]{' + status + '}\n'
    +                        + '    Got: [red]{' + response.statusCode + '}')
    +                );
    +            }
    +
    +            // Assert response headers
    +            if (res.headers) {
    +                var keys = Object.keys(res.headers);
    +                for (var i = 0, len = keys.length; i &lt; len; ++i) {
    +                    var name = keys[i],
    +                        actual = response.headers[name.toLowerCase()],
    +                        expected = res.headers[name],
    +                        eql = expected instanceof RegExp
    +                          ? expected.test(actual)
    +                          : expected == actual;
    +                    assert.ok(
    +                        eql,
    +                        msg + colorize('Invalid response header [bold]{' + name + '}.\n'
    +                            + '    Expected: [green]{' + expected + '}\n'
    +                            + '    Got: [red]{' + actual + '}')
    +                    );
    +                }
    +            }
    +
    +            // Callback
    +            callback(response);
    +        });
    +    });
    +    request.end();
    +};
    +
    +

    Pad the given string to the maximum width provided.

    + +

    + +
    • param: String str

    • param: Number width

    • return: String

    +
    +
    function lpad(str, width) {
    +    str = String(str);
    +    var n = width - str.length;
    +    if (n &lt; 1) return str;
    +    while (n--) str = ' ' + str;
    +    return str;
    +}
    +
    +

    Pad the given string to the maximum width provided.

    + +

    + +
    • param: String str

    • param: Number width

    • return: String

    +
    +
    function rpad(str, width) {
    +    str = String(str);
    +    var n = width - str.length;
    +    if (n &lt; 1) return str;
    +    while (n--) str = str + ' ';
    +    return str;
    +}
    +
    +

    Report test coverage.

    + +

    + +
    • param: Object cov

    +
    +
    function reportCoverage(cov) {
    +    populateCoverage(cov);
    +    // Stats
    +    print('\n   [bold]{Test Coverage}\n');
    +    var sep = '   +------------------------------------------+----------+------+------+--------+',
    +        lastSep = '                                              +----------+------+------+--------+';
    +    sys.puts(sep);
    +    sys.puts('   | filename                                 | coverage | LOC  | SLOC | missed |');
    +    sys.puts(sep);
    +    for (var name in cov) {
    +        var file = cov[name];
    +        if (Array.isArray(file)) {
    +            sys.print('   | ' + rpad(name, 40));
    +            sys.print(' | ' + lpad(file.coverage.toFixed(2), 8));
    +            sys.print(' | ' + lpad(file.LOC, 4));
    +            sys.print(' | ' + lpad(file.SLOC, 4));
    +            sys.print(' | ' + lpad(file.totalMisses, 6));
    +            sys.print(' |\n');
    +        }
    +    }
    +    sys.puts(sep);
    +    sys.print('     ' + rpad('', 40));
    +    sys.print(' | ' + lpad(cov.coverage.toFixed(2), 8));
    +    sys.print(' | ' + lpad(cov.LOC, 4));
    +    sys.print(' | ' + lpad(cov.SLOC, 4));
    +    sys.print(' | ' + lpad(cov.totalMisses, 6));
    +    sys.print(' |\n');
    +    sys.puts(lastSep);
    +    // Source
    +    for (var name in cov) {
    +        if (name.match(/\.js$/)) {
    +            var file = cov[name];
    +            print('\n   [bold]{' + name + '}:');
    +            print(file.source);
    +            sys.print('\n');
    +        }
    +    }
    +}
    +
    +

    Populate code coverage data.

    + +

    + +
    • param: Object cov

    +
    +
    function populateCoverage(cov) {
    +    cov.LOC = 
    +    cov.SLOC =
    +    cov.totalFiles =
    +    cov.totalHits =
    +    cov.totalMisses = 
    +    cov.coverage = 0;
    +    for (var name in cov) {
    +        var file = cov[name];
    +        if (Array.isArray(file)) {
    +            // Stats
    +            ++cov.totalFiles;
    +            cov.totalHits += file.totalHits = coverage(file, true);
    +            cov.totalMisses += file.totalMisses = coverage(file, false);
    +            file.totalLines = file.totalHits + file.totalMisses;
    +            cov.SLOC += file.SLOC = file.totalLines;
    +            if (!file.source) file.source = [];
    +            cov.LOC += file.LOC = file.source.length;
    +            file.coverage = (file.totalHits / file.totalLines) * 100;
    +            // Source
    +            var width = file.source.length.toString().length;
    +            file.source = file.source.map(function(line, i){
    +                ++i;
    +                var hits = file[i] === 0 ? 0 : (file[i] || ' ');
    +                if (!boring) {
    +                    if (hits === 0) {
    +                        hits = '\x1b[31m' + hits + '\x1b[0m';
    +                        line = '\x1b[41m' + line + '\x1b[0m';
    +                    } else {
    +                        hits = '\x1b[32m' + hits + '\x1b[0m';
    +                    }
    +                }
    +                return '\n     ' + lpad(i, width) + ' | ' + hits + ' | ' + line;
    +            }).join('');
    +        }
    +    }
    +    cov.coverage = (cov.totalHits / cov.SLOC) * 100;
    +}
    +
    +

    Total coverage for the given file data.

    + +

    + +
    • param: Array data

    • return: Type

    +
    +
    function coverage(data, val) {
    +    var n = 0;
    +    for (var i = 0, len = data.length; i &lt; len; ++i) {
    +        if (data[i] !== undefined &amp;&amp; data[i] == val) ++n;
    +    }
    +    return n;  
    +}
    +
    +

    Run the given test files, or try test/*.

    + +

    + +
    • param: Array files

    +
    +
    function run(files) {
    +    if (!files.length) {
    +        try {
    +            files = fs.readdirSync('test').map(function(file){
    +                return 'test/' + file;
    +            });
    +        } catch (err) {
    +            print('\n  failed to load tests in [bold]{./test}\n');
    +            ++failures;
    +            process.exit(1);
    +        }
    +    }
    +    if (watch) watchFiles(files);
    +    runFiles(files);
    +}
    +
    +

    Show the cursor when show is true, otherwise hide it.

    + +

    + +
    • param: Boolean show

    +
    +
    function cursor(show) {
    +    if (show) {
    +        sys.print('\x1b[?25h');
    +    } else {
    +        sys.print('\x1b[?25l');
    +    }
    +}
    +
    +

    Run the given test files.

    + +

    + +
    • param: Array files

    +
    +
    function runFiles(files) {
    +    if (serial) {
    +        (function next(){
    +            if (files.length) {
    +                runFile(files.shift(), next);
    +            }
    +        })();
    +    } else {
    +      files.forEach(runFile);
    +    }
    +}
    +
    +

    Run tests for the given file, callback fn() when finished.

    + +

    + +
    • param: String file

    • param: Function fn

    +
    +
    function runFile(file, fn) {
    +    if (file.match(/\.js$/)) {
    +        var title = path.basename(file),
    +            file = path.join(cwd, file),
    +            mod = require(file.replace(/\.js$/, ''));
    +        (function check(){
    +           var len = Object.keys(mod).length;
    +           if (len) {
    +               runSuite(title, mod, fn);
    +           } else {
    +               setTimeout(check, 20);
    +           }
    +        })();
    +    }
    +}
    +
    +

    Clear the module cache for the given file.

    + +

    + +
    • param: String file

    +
    +
    function clearCache(file) {
    +    var keys = Object.keys(module.moduleCache);
    +    for (var i = 0, len = keys.length; i &lt; len; ++i) {
    +        var key = keys[i];
    +        if (key.indexOf(file) === key.length - file.length) {
    +            delete module.moduleCache[key];
    +        }
    +    }
    +}
    +
    +

    Watch the given files for changes.

    + +

    + +
    • param: Array files

    +
    +
    function watchFiles(files) {
    +    var p = 0,
    +        c = ['▫   ', '▫▫  ', '▫▫▫ ', ' ▫▫▫',
    +             '  ▫▫', '   ▫', '   ▫', '  ▫▫',
    +             '▫▫▫ ', '▫▫  ', '▫   '],
    +        l = c.length;
    +    cursor(false);
    +    setInterval(function(){
    +        sys.print(colorize('  [green]{' + c[p++ % l] + '} watching\r'));
    +    }, 100);
    +    files.forEach(function(file){
    +        fs.watchFile(file, { interval: 100 }, function(curr, prev){
    +            if (curr.mtime &gt; prev.mtime) {
    +                print('  [yellow]{◦} ' + file);
    +                clearCache(file);
    +                runFile(file);
    +            }
    +        });
    +    });
    +}
    +
    +

    Report err for the given test and suite.

    + +

    + +
    • param: String suite

    • param: String test

    • param: Error err

    +
    +
    function error(suite, test, err) {
    +    ++failures;
    +    var name = err.name,
    +        stack = err.stack.replace(err.name, ''),
    +        label = test === 'uncaught'
    +            ? test
    +            : suite + ' ' + test;
    +    print('\n   [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n');
    +    if (watch) notify(label + ' failed');
    +}
    +
    +

    Run the given tests, callback fn() when finished.

    + +

    + +
    • param: String title

    • param: Object tests

    • param: Function fn

    +
    +
    var dots = 0;
    +function runSuite(title, tests, fn) {
    +    // Keys
    +    var keys = only.length
    +        ? only.slice(0)
    +        : Object.keys(tests);
    +
    +    // Setup
    +    var setup = tests.setup || function(fn){ fn(); };
    +
    +    // Iterate tests
    +    (function next(){
    +        if (keys.length) {
    +            var key,
    +                test = tests[key = keys.shift()];
    +            // Non-tests
    +            if (key === 'setup') return next();
    +
    +            // Run test
    +            if (test) {
    +                try {
    +                    ++testcount;
    +                    assert.testTitle = key;
    +                    if (serial) {
    +                        if (!watch) {
    +                            sys.print('.');
    +                            if (++dots % 25 === 0) sys.print('\n');
    +                        }
    +                        setup(function(){
    +                            if (test.length &lt; 1) {
    +                                test();
    +                                next();
    +                            } else {
    +                                var id = setTimeout(function(){
    +                                    throw new Error(&quot;'" + key + "' timed out&quot;);
    +                                }, timeout);
    +                                test(function(){
    +                                    clearTimeout(id);
    +                                    next();
    +                                });
    +                            } 
    +                        });
    +                    } else {
    +                        test(function(fn){
    +                            process.addListener('beforeExit', function(){
    +                                try {
    +                                    fn();
    +                                } catch (err) {
    +                                    error(title, key, err);
    +                                }
    +                            });
    +                        });
    +                    }
    +                } catch (err) {
    +                    error(title, key, err);
    +                }
    +            }
    +            if (!serial) next();
    +        } else if (serial) {
    +          fn();
    +        }
    +    })();
    +}
    +
    +

    Report exceptions. +

    +
    +
    function report() {
    +    process.emit('beforeExit');
    +    if (failures) {
    +        print('\n   [bold]{Failures}: [red]{' + failures + '}\n\n');
    +        notify('Failures: ' + failures);
    +    } else {
    +        if (serial) print('');
    +        print('\n   [green]{100%} ' + testcount + ' tests\n');
    +        notify('100% ok');
    +    }
    +    if (typeof _$jscoverage === 'object') {
    +        reportCoverage(_$jscoverage);
    +    }
    +}
    +
    +

    Growl notify the given msg.

    + +

    + +
    • param: String msg

    +
    +
    function notify(msg) {
    +    if (growl) {
    +        childProcess.exec('growlnotify -name Expresso -m "' + msg + '"');
    +    }
    +}
    +
    +// Report uncaught exceptions
    +
    +process.addListener('uncaughtException', function(err){
    +    error('uncaught', 'uncaught', err);
    +});
    +
    +// Show cursor
    +
    +['INT', 'TERM', 'QUIT'].forEach(function(sig){
    +    process.addListener('SIG' + sig, function(){
    +        cursor(true);
    +        process.exit(1);
    +    });
    +});
    +
    +// Report test coverage when available
    +// and emit "beforeExit" event to perform
    +// final assertions
    +
    +var orig = process.emit;
    +process.emit = function(event){
    +    if (event === 'exit') {
    +        report();
    +        process.reallyExit(failures);
    +    }
    +    orig.apply(this, arguments);
    +};
    +
    +// Run test files
    +
    +if (!defer) run(files);
    +
    +
    \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/index.html b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/index.html new file mode 100644 index 0000000..064313f --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/index.html @@ -0,0 +1,377 @@ + + + Expresso - TDD Framework For Node + + + + + Fork me on GitHub + +
    +

    Expresso

    +
    +

    NAME

    +

    + index +

    +

    Expresso is a JavaScript TDD framework written for nodejs. Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more.

    + +

    Features

    + +
      +
    • light-weight
    • +
    • intuitive async support
    • +
    • intuitive test runner executable
    • +
    • test coverage support and reporting via node-jscoverage
    • +
    • uses and extends the core assert module
    • +
    • assert.eql() alias of assert.deepEqual()
    • +
    • assert.response() http response utility
    • +
    • assert.includes()
    • +
    • assert.isNull()
    • +
    • assert.isUndefined()
    • +
    • assert.isNotNull()
    • +
    • assert.isDefined()
    • +
    • assert.match()
    • +
    • assert.length()
    • +
    + + +

    Installation

    + +

    To install both expresso and node-jscoverage run +the command below, which will first compile node-jscoverage:

    + +
    $ make install
    +
    + +

    To install expresso alone without coverage reporting run:

    + +
    $ make install-expresso
    +
    + +

    Install via npm:

    + +
    $ npm install expresso
    +
    + +

    Examples

    + +

    To define tests we simply export several functions:

    + +
    exports['test String#length'] = function(){
    +    assert.equal(6, 'foobar'.length);
    +};
    +
    + +

    Alternatively for large numbers of tests you may want to +export your own object containing the tests, however this +is essentially the as above:

    + +
    module.exports = {
    +    'test String#length': function(){
    +        assert.equal(6, 'foobar'.length);
    +    }
    +};
    +
    + +

    If you prefer not to use quoted keys:

    + +
    exports.testsStringLength = function(){
    +    assert.equal(6, 'foobar'.length);
    +};
    +
    + +

    The argument passed to each callback is beforeExit, +which is typically used to assert that callbacks have been +invoked.

    + +
    exports.testAsync = function(beforeExit){
    +    var n = 0;
    +    setTimeout(function(){
    +        ++n;
    +        assert.ok(true);
    +    }, 200);
    +    setTimeout(function(){
    +        ++n;
    +        assert.ok(true);
    +    }, 200);
    +    beforeExit(function(){
    +        assert.equal(2, n, 'Ensure both timeouts are called');
    +    });
    +};
    +
    + +

    Assert Utilities

    + +

    assert.isNull(val[, msg])

    + +

    Asserts that the given val is null.

    + +
    assert.isNull(null);
    +
    + +

    assert.isNotNull(val[, msg])

    + +

    Asserts that the given val is not null.

    + +
    assert.isNotNull(undefined);
    +assert.isNotNull(false);
    +
    + +

    assert.isUndefined(val[, msg])

    + +

    Asserts that the given val is undefined.

    + +
    assert.isUndefined(undefined);
    +
    + +

    assert.isDefined(val[, msg])

    + +

    Asserts that the given val is not undefined.

    + +
    assert.isDefined(null);
    +assert.isDefined(false);
    +
    + +

    assert.match(str, regexp[, msg])

    + +

    Asserts that the given str matches regexp.

    + +
    assert.match('foobar', /^foo(bar)?/);
    +assert.match('foo', /^foo(bar)?/);
    +
    + +

    assert.length(val, n[, msg])

    + +

    Assert that the given val has a length of n.

    + +
    assert.length([1,2,3], 3);
    +assert.length('foo', 3);
    +
    + +

    assert.type(obj, type[, msg])

    + +

    Assert that the given obj is typeof type.

    + +
    assert.type(3, 'number');
    +
    + +

    assert.eql(a, b[, msg])

    + +

    Assert that object b is equal to object a. This is an +alias for the core assert.deepEqual() method which does complex +comparisons, opposed to assert.equal() which uses ==.

    + +
    assert.eql('foo', 'foo');
    +assert.eql([1,2], [1,2]);
    +assert.eql({ foo: 'bar' }, { foo: 'bar' });
    +
    + +

    assert.includes(obj, val[, msg])

    + +

    Assert that obj is within val. This method supports Array_s +and Strings_s.

    + +
    assert.includes([1,2,3], 3);
    +assert.includes('foobar', 'foo');
    +assert.includes('foobar', 'bar');
    +
    + +

    assert.response(server, req, res|fn[, msg|fn])

    + +

    Performs assertions on the given server, which should not call +listen(), as this is handled internally by expresso and the server +is killed after all responses have completed. This method works with +any http.Server instance, so Connect and Express servers will work +as well.

    + +

    The req object may contain:

    + +
      +
    • url request url
    • +
    • timeout timeout in milliseconds
    • +
    • method HTTP method
    • +
    • data request body
    • +
    • headers headers object
    • +
    + + +

    The res object may be a callback function which +receives the response for assertions, or an object +which is then used to perform several assertions +on the response with the following properties:

    + +
      +
    • body assert response body (regexp or string)
    • +
    • status assert response status code
    • +
    • header assert that all given headers match (unspecified are ignored, use a regexp or string)
    • +
    + + +

    When providing res you may then also pass a callback function +as the fourth argument for additional assertions.

    + +

    Below are some examples:

    + +
    assert.response(server, {
    +    url: '/', timeout: 500
    +}, {
    +    body: 'foobar'
    +});
    +
    +assert.response(server, {
    +    url: '/',
    +    method: 'GET'
    +},{
    +    body: '{"name":"tj"}',
    +    status: 200,
    +    headers: {
    +        'Content-Type': 'application/json; charset=utf8',
    +        'X-Foo': 'bar'
    +    }
    +});
    +
    +assert.response(server, {
    +    url: '/foo',
    +    method: 'POST',
    +    data: 'bar baz'
    +},{
    +    body: '/foo bar baz',
    +    status: 200
    +}, 'Test POST');
    +
    +assert.response(server, {
    +    url: '/foo',
    +    method: 'POST',
    +    data: 'bar baz'
    +},{
    +    body: '/foo bar baz',
    +    status: 200
    +}, function(res){
    +    // All done, do some more tests if needed
    +});
    +
    +assert.response(server, {
    +    url: '/'
    +}, function(res){
    +    assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback');
    +});
    +
    + +

    expresso(1)

    + +

    To run a single test suite (file) run:

    + +
    $ expresso test/a.test.js
    +
    + +

    To run several suites we may simply append another:

    + +
    $ expresso test/a.test.js test/b.test.js
    +
    + +

    We can also pass a whitelist of tests to run within all suites:

    + +
    $ expresso --only "foo()" --only "bar()"
    +
    + +

    Or several with one call:

    + +
    $ expresso --only "foo(), bar()"
    +
    + +

    Globbing is of course possible as well:

    + +
    $ expresso test/*
    +
    + +

    When expresso is called without any files, test/* is the default, +so the following is equivalent to the command above:

    + +
    $ expresso
    +
    + +

    If you wish to unshift a path to require.paths before +running tests, you may use the -I or --include flag.

    + +
    $ expresso --include lib test/*
    +
    + +

    The previous example is typically what I would recommend, since expresso +supports test coverage via node-jscoverage (bundled with expresso), +so you will need to expose an instrumented version of you library.

    + +

    To instrument your library, simply run node-jscoverage, +passing the src and dest directories:

    + +
    $ node-jscoverage lib lib-cov
    +
    + +

    Now we can run our tests again, using the lib-cov directory that has been +instrumented with coverage statements:

    + +
    $ expresso -I lib-cov test/*
    +
    + +

    The output will look similar to below, depending on your test coverage of course :)

    + +

    node coverage

    + +

    To make this process easier expresso has the -c or --cov which essentially +does the same as the two commands above. The following two commands will +run the same tests, however one will auto-instrument, and unshift lib-cov, +and the other will run tests normally:

    + +
    $ expresso -I lib test/*
    +$ expresso -I lib --cov test/*
    +
    + +

    Currently coverage is bound to the lib directory, however in the +future --cov will most likely accept a path.

    + +

    Async Exports

    + +

    Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the exports.foo = function(){}; syntax is supported for this:

    + +
    setTimeout(function(){
    +    exports['test async exports'] = function(){
    +        assert.ok('wahoo');
    +    };
    +}, 100);
    +
    + +
    +
    + + \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/index.md b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/index.md new file mode 100644 index 0000000..489f931 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/index.md @@ -0,0 +1,290 @@ + +[Expresso](http://github.com/visionmedia/expresso) is a JavaScript [TDD](http://en.wikipedia.org/wiki/Test-driven_development) framework written for [nodejs](http://nodejs.org). Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more. + +## Features + + - light-weight + - intuitive async support + - intuitive test runner executable + - test coverage support and reporting via [node-jscoverage](http://github.com/visionmedia/node-jscoverage) + - uses and extends the core _assert_ module + - `assert.eql()` alias of `assert.deepEqual()` + - `assert.response()` http response utility + - `assert.includes()` + - `assert.isNull()` + - `assert.isUndefined()` + - `assert.isNotNull()` + - `assert.isDefined()` + - `assert.match()` + - `assert.length()` + +## Installation + +To install both expresso _and_ node-jscoverage run +the command below, which will first compile node-jscoverage: + + $ make install + +To install expresso alone without coverage reporting run: + + $ make install-expresso + +Install via npm: + + $ npm install expresso + +## Examples + +To define tests we simply export several functions: + + exports['test String#length'] = function(){ + assert.equal(6, 'foobar'.length); + }; + +Alternatively for large numbers of tests you may want to +export your own object containing the tests, however this +is essentially the as above: + + module.exports = { + 'test String#length': function(){ + assert.equal(6, 'foobar'.length); + } + }; + +If you prefer not to use quoted keys: + + exports.testsStringLength = function(){ + assert.equal(6, 'foobar'.length); + }; + +The argument passed to each callback is _beforeExit_, +which is typically used to assert that callbacks have been +invoked. + + exports.testAsync = function(beforeExit){ + var n = 0; + setTimeout(function(){ + ++n; + assert.ok(true); + }, 200); + setTimeout(function(){ + ++n; + assert.ok(true); + }, 200); + beforeExit(function(){ + assert.equal(2, n, 'Ensure both timeouts are called'); + }); + }; + +## Assert Utilities + +### assert.isNull(val[, msg]) + +Asserts that the given _val_ is _null_. + + assert.isNull(null); + +### assert.isNotNull(val[, msg]) + +Asserts that the given _val_ is not _null_. + + assert.isNotNull(undefined); + assert.isNotNull(false); + +### assert.isUndefined(val[, msg]) + +Asserts that the given _val_ is _undefined_. + + assert.isUndefined(undefined); + +### assert.isDefined(val[, msg]) + +Asserts that the given _val_ is not _undefined_. + + assert.isDefined(null); + assert.isDefined(false); + +### assert.match(str, regexp[, msg]) + +Asserts that the given _str_ matches _regexp_. + + assert.match('foobar', /^foo(bar)?/); + assert.match('foo', /^foo(bar)?/); + +### assert.length(val, n[, msg]) + +Assert that the given _val_ has a length of _n_. + + assert.length([1,2,3], 3); + assert.length('foo', 3); + +### assert.type(obj, type[, msg]) + +Assert that the given _obj_ is typeof _type_. + + assert.type(3, 'number'); + +### assert.eql(a, b[, msg]) + +Assert that object _b_ is equal to object _a_. This is an +alias for the core _assert.deepEqual()_ method which does complex +comparisons, opposed to _assert.equal()_ which uses _==_. + + assert.eql('foo', 'foo'); + assert.eql([1,2], [1,2]); + assert.eql({ foo: 'bar' }, { foo: 'bar' }); + +### assert.includes(obj, val[, msg]) + +Assert that _obj_ is within _val_. This method supports _Array_s +and _Strings_s. + + assert.includes([1,2,3], 3); + assert.includes('foobar', 'foo'); + assert.includes('foobar', 'bar'); + +### assert.response(server, req, res|fn[, msg|fn]) + +Performs assertions on the given _server_, which should _not_ call +listen(), as this is handled internally by expresso and the server +is killed after all responses have completed. This method works with +any _http.Server_ instance, so _Connect_ and _Express_ servers will work +as well. + +The _req_ object may contain: + + - _url_ request url + - _timeout_ timeout in milliseconds + - _method_ HTTP method + - _data_ request body + - _headers_ headers object + +The _res_ object may be a callback function which +receives the response for assertions, or an object +which is then used to perform several assertions +on the response with the following properties: + + - _body_ assert response body (regexp or string) + - _status_ assert response status code + - _header_ assert that all given headers match (unspecified are ignored, use a regexp or string) + +When providing _res_ you may then also pass a callback function +as the fourth argument for additional assertions. + +Below are some examples: + + assert.response(server, { + url: '/', timeout: 500 + }, { + body: 'foobar' + }); + + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8', + 'X-Foo': 'bar' + } + }); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, 'Test POST'); + + assert.response(server, { + url: '/foo', + method: 'POST', + data: 'bar baz' + },{ + body: '/foo bar baz', + status: 200 + }, function(res){ + // All done, do some more tests if needed + }); + + assert.response(server, { + url: '/' + }, function(res){ + assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback'); + }); + + +## expresso(1) + +To run a single test suite (file) run: + + $ expresso test/a.test.js + +To run several suites we may simply append another: + + $ expresso test/a.test.js test/b.test.js + +We can also pass a whitelist of tests to run within all suites: + + $ expresso --only "foo()" --only "bar()" + +Or several with one call: + + $ expresso --only "foo(), bar()" + +Globbing is of course possible as well: + + $ expresso test/* + +When expresso is called without any files, _test/*_ is the default, +so the following is equivalent to the command above: + + $ expresso + +If you wish to unshift a path to `require.paths` before +running tests, you may use the `-I` or `--include` flag. + + $ expresso --include lib test/* + +The previous example is typically what I would recommend, since expresso +supports test coverage via [node-jscoverage](http://github.com/visionmedia/node-jscoverage) (bundled with expresso), +so you will need to expose an instrumented version of you library. + +To instrument your library, simply run [node-jscoverage](http://github.com/visionmedia/node-jscoverage), +passing the _src_ and _dest_ directories: + + $ node-jscoverage lib lib-cov + +Now we can run our tests again, using the _lib-cov_ directory that has been +instrumented with coverage statements: + + $ expresso -I lib-cov test/* + +The output will look similar to below, depending on your test coverage of course :) + +![node coverage](http://dl.dropbox.com/u/6396913/cov.png) + +To make this process easier expresso has the _-c_ or _--cov_ which essentially +does the same as the two commands above. The following two commands will +run the same tests, however one will auto-instrument, and unshift _lib-cov_, +and the other will run tests normally: + + $ expresso -I lib test/* + $ expresso -I lib --cov test/* + +Currently coverage is bound to the _lib_ directory, however in the +future `--cov` will most likely accept a path. + +## Async Exports + +Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the _exports.foo = function(){};_ syntax is supported for this: + + setTimeout(function(){ + exports['test async exports'] = function(){ + assert.ok('wahoo'); + }; + }, 100); diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/layout/foot.html b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/layout/foot.html new file mode 100644 index 0000000..44d85e9 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/layout/foot.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/layout/head.html b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/layout/head.html new file mode 100644 index 0000000..567f62e --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/docs/layout/head.html @@ -0,0 +1,42 @@ + + + Expresso - TDD Framework For Node + + + + + Fork me on GitHub + +
    +

    Expresso

    diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/lib/bar.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/lib/bar.js new file mode 100644 index 0000000..e15aad4 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/lib/bar.js @@ -0,0 +1,4 @@ + +exports.bar = function(msg){ + return msg || 'bar'; +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/lib/foo.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/lib/foo.js new file mode 100644 index 0000000..15701a5 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/lib/foo.js @@ -0,0 +1,16 @@ + +exports.foo = function(msg){ + if (msg) { + return msg; + } else { + return generateFoo(); + } +}; + +function generateFoo() { + return 'foo'; +} + +function Foo(msg){ + this.msg = msg || 'foo'; +} diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/package.json b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/package.json new file mode 100644 index 0000000..569a54b --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/package.json @@ -0,0 +1,12 @@ +{ "name": "expresso", + "version": "0.7.2", + "description": "TDD framework, light-weight, fast, CI-friendly", + "author": "TJ Holowaychuk ", + "bin": { + "expresso": "./bin/expresso", + "node-jscoverage": "./deps/jscoverage/node-jscoverage" + }, + "scripts": { + "preinstall": "make deps/jscoverage/node-jscoverage" + } +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/assert.test.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/assert.test.js new file mode 100644 index 0000000..f822595 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/assert.test.js @@ -0,0 +1,91 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert'); + +module.exports = { + 'assert.eql()': function(){ + assert.equal(assert.deepEqual, assert.eql); + }, + + 'assert.type()': function(){ + assert.type('foobar', 'string'); + assert.type(2, 'number'); + assert.throws(function(){ + assert.type([1,2,3], 'string'); + }); + }, + + 'assert.includes()': function(){ + assert.includes('some random string', 'dom'); + assert.throws(function(){ + assert.include('some random string', 'foobar'); + }); + + assert.includes(['foo', 'bar'], 'bar'); + assert.includes(['foo', 'bar'], 'foo'); + assert.includes([1,2,3], 3); + assert.includes([1,2,3], 2); + assert.includes([1,2,3], 1); + assert.throws(function(){ + assert.includes(['foo', 'bar'], 'baz'); + }); + + assert.throws(function(){ + assert.includes({ wrong: 'type' }, 'foo'); + }); + }, + + 'assert.isNull()': function(){ + assert.isNull(null); + assert.throws(function(){ + assert.isNull(undefined); + }); + assert.throws(function(){ + assert.isNull(false); + }); + }, + + 'assert.isUndefined()': function(){ + assert.isUndefined(undefined); + assert.throws(function(){ + assert.isUndefined(null); + }); + assert.throws(function(){ + assert.isUndefined(false); + }); + }, + + 'assert.isNotNull()': function(){ + assert.isNotNull(false); + assert.isNotNull(undefined); + assert.throws(function(){ + assert.isNotNull(null); + }); + }, + + 'assert.isDefined()': function(){ + assert.isDefined(false); + assert.isDefined(null); + assert.throws(function(){ + assert.isDefined(undefined); + }); + }, + + 'assert.match()': function(){ + assert.match('foobar', /foo(bar)?/); + assert.throws(function(){ + assert.match('something', /rawr/); + }); + }, + + 'assert.length()': function(){ + assert.length('test', 4); + assert.length([1,2,3,4], 4); + assert.throws(function(){ + assert.length([1,2,3], 4); + }); + } +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/async.test.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/async.test.js new file mode 100644 index 0000000..d1d2036 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/async.test.js @@ -0,0 +1,12 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert'); + +setTimeout(function(){ + exports['test async exports'] = function(){ + assert.ok('wahoo'); + }; +}, 100); \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/bar.test.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/bar.test.js new file mode 100644 index 0000000..cfc2e11 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/bar.test.js @@ -0,0 +1,13 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , bar = require('bar'); + +module.exports = { + 'bar()': function(){ + assert.equal('bar', bar.bar()); + } +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/foo.test.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/foo.test.js new file mode 100644 index 0000000..ee5cff3 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/foo.test.js @@ -0,0 +1,14 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , foo = require('foo'); + +module.exports = { + 'foo()': function(){ + assert.equal('foo', foo.foo()); + assert.equal('foo', foo.foo()); + } +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/http.test.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/http.test.js new file mode 100644 index 0000000..1f9d249 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/http.test.js @@ -0,0 +1,146 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , http = require('http'); + +var server = http.createServer(function(req, res){ + if (req.method === 'GET') { + if (req.url === '/delay') { + setTimeout(function(){ + res.writeHead(200, {}); + res.end('delayed'); + }, 200); + } else { + var body = JSON.stringify({ name: 'tj' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf8', + 'Content-Length': body.length + }); + res.end(body); + } + } else { + var body = ''; + req.setEncoding('utf8'); + req.on('data', function(chunk){ body += chunk }); + req.on('end', function(){ + res.writeHead(200, {}); + res.end(req.url + ' ' + body); + }); + } +}); + +var delayedServer = http.createServer(function(req, res){ + res.writeHead(200); + res.end('it worked'); +}); + +var oldListen = delayedServer.listen; +delayedServer.listen = function(){ + var args = arguments; + setTimeout(function(){ + oldListen.apply(delayedServer, args); + }, 100); +}; + +module.exports = { + 'test assert.response(req, res, fn)': function(beforeExit){ + var calls = 0; + + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8' + } + }, function(res){ + ++calls; + assert.ok(res); + }); + + beforeExit(function(){ + assert.equal(1, calls); + }) + }, + + 'test assert.response(req, fn)': function(beforeExit){ + var calls = 0; + + assert.response(server, { + url: '/foo' + }, function(res){ + ++calls; + assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback'); + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + }, + + 'test assert.response() delay': function(beforeExit){ + var calls = 0; + + assert.response(server, + { url: '/delay', timeout: 1500 }, + { body: 'delayed' }, + function(){ + ++calls; + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + }, + + 'test assert.response() regexp': function(beforeExit){ + var calls = 0; + + assert.response(server, + { url: '/foo', method: 'POST', data: 'foobar' }, + { body: /^\/foo foo(bar)?/ }, + function(){ + ++calls; + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + }, + + 'test assert.response() regexp headers': function(beforeExit){ + var calls = 0; + + assert.response(server, + { url: '/' }, + { body: '{"name":"tj"}', headers: { 'Content-Type': /^application\/json/ } }, + function(){ + ++calls; + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + }, + + // [!] if this test doesn't pass, an uncaught ECONNREFUSED will display + 'test assert.response() with deferred listen()': function(beforeExit){ + var calls = 0; + + assert.response(delayedServer, + { url: '/' }, + { body: 'it worked' }, + function(){ + ++calls; + }); + + beforeExit(function(){ + assert.equal(1, calls); + }); + } +}; diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/serial/async.test.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/serial/async.test.js new file mode 100644 index 0000000..c596d5c --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/serial/async.test.js @@ -0,0 +1,39 @@ + +var assert = require('assert') + , setup = 0 + , order = []; + +module.exports = { + setup: function(done){ + ++setup; + done(); + }, + + a: function(done){ + assert.equal(1, setup); + order.push('a'); + setTimeout(function(){ + done(); + }, 500); + }, + + b: function(done){ + assert.equal(2, setup); + order.push('b'); + setTimeout(function(){ + done(); + }, 200); + }, + + c: function(done){ + assert.equal(3, setup); + order.push('c'); + setTimeout(function(){ + done(); + }, 1000); + }, + + d: function(){ + assert.eql(order, ['a', 'b', 'c']); + } +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/serial/http.test.js b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/serial/http.test.js new file mode 100644 index 0000000..7783eb5 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/expresso/test/serial/http.test.js @@ -0,0 +1,48 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') + , http = require('http'); + +var server = http.createServer(function(req, res){ + if (req.method === 'GET') { + if (req.url === '/delay') { + setTimeout(function(){ + res.writeHead(200, {}); + res.end('delayed'); + }, 200); + } else { + var body = JSON.stringify({ name: 'tj' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf8', + 'Content-Length': body.length + }); + res.end(body); + } + } else { + var body = ''; + req.setEncoding('utf8'); + req.addListener('data', function(chunk){ body += chunk }); + req.addListener('end', function(){ + res.writeHead(200, {}); + res.end(req.url + ' ' + body); + }); + } +}); + +module.exports = { + 'test assert.response()': function(done){ + assert.response(server, { + url: '/', + method: 'GET' + },{ + body: '{"name":"tj"}', + status: 200, + headers: { + 'Content-Type': 'application/json; charset=utf8' + } + }, done); + } +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/.gitmodules b/NodeDrawing/node_modules/express/node_modules/qs/support/should/.gitmodules new file mode 100644 index 0000000..ffe0dcb --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/.gitmodules @@ -0,0 +1,3 @@ +[submodule "support/expresso"] + path = support/expresso + url = git://github.com/visionmedia/expresso.git diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/History.md b/NodeDrawing/node_modules/express/node_modules/qs/support/should/History.md new file mode 100644 index 0000000..cb95b57 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/History.md @@ -0,0 +1,22 @@ + +0.0.4 / 2010-11-24 +================== + + * Added `.ok` to assert truthfulness + * Added `.arguments` + * Fixed double required bug. [thanks dominictarr] + +0.0.3 / 2010-11-19 +================== + + * Added `true` / `false` assertions + +0.0.2 / 2010-11-19 +================== + + * Added chaining support + +0.0.1 / 2010-11-19 +================== + + * Initial release diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/Makefile b/NodeDrawing/node_modules/express/node_modules/qs/support/should/Makefile new file mode 100644 index 0000000..a2f2a41 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/Makefile @@ -0,0 +1,6 @@ + +test: + @./support/expresso/bin/expresso \ + -I lib + +.PHONY: test \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/Readme.md b/NodeDrawing/node_modules/express/node_modules/qs/support/should/Readme.md new file mode 100644 index 0000000..7c5c0ac --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/Readme.md @@ -0,0 +1,248 @@ + _should_ is an expressive, test framework agnostic, assertion library for [node](http://nodejs.org). + +_should_ literally extends node's _assert_ module, in fact, it is node's assert module, for example `should.equal(str, 'foo')` will work, just as `assert.equal(str, 'foo')` would, and `should.AssertionError` **is** `asset.AssertionError`, meaning any test framework supporting this constructor will function properly with _should_. + +## Example + + var user = { + name: 'tj' + , pets: ['tobi', 'loki', 'jane', 'bandit'] + }; + + user.should.have.property('name', 'tj'); + user.should.have.property('pets').with.lengthOf(4) + +## Installation + + $ npm install should + +## modifiers + + _should_'s assertion chaining provides an expressive way to build up an assertion, along with dummy getters such as _an_, _have_, and _be_, provided are what I am simply calling **modifiers**, which have a meaning effect on the assertion. An example of this is the _not_ getter, which negates the meaning, aka `user.should.not.have.property('name')`. In the previous example note the use of _have_, as we could omit it and still construct a valid assertion. + +Some modifiers such as _include_ only have an effect with specific assertion methods, for example when asserting a substring like so: `str.should.include.string('test')`, we could omit _include_, but it helps express the meaning, however _keys_ has a strict effect, unless the _include_ modifier is used. + +## chaining assertions + +Some assertions can be chained, for example if a property is volatile we can first assert property existence: + + user.should.have.property('pets').with.lengthOf(4) + +which is essentially equivalent to below, however the property may not exist: + + user.pets.should.have.lengthOf(4) + +our dummy getters such as _and_ also help express chaining: + + user.should.be.a('object').and.have.property('name', 'tj') + +## ok + +Assert truthfulness: + + true.should.be.ok + 'yay'.should.be.ok + (1).should.be.ok + +or negated: + + false.should.not.be.ok + ''.should.not.be.ok + (0).should.not.be.ok + +## true + +Assert === true: + + true.should.be.true + '1'.should.not.be.true + +## false + +Assert === false: + + false.should.be.false + (0).should.not.be.false + +## arguments + +Assert `Arguments`: + + var args = (function(){ return arguments; })(1,2,3); + args.should.be.arguments; + [].should.not.be.arguments; + +## empty + +Asserts that length is 0: + + [].should.be.empty + ''.should.be.empty + ({ length: 0 }).should.be.empty + +## eql + +equality: + + ({ foo: 'bar' }).should.eql({ foo: 'bar' }) + [1,2,3].should.eql([1,2,3]) + +## equal + +strict equality: + + should.strictEqual(undefined, value) + should.strictEqual(false, value) + (4).should.equal(4) + 'test'.should.equal('test') + [1,2,3].should.not.equal([1,2,3]) + +## within + +Assert inclusive numeric range: + + user.age.should.be.within(5, 50) + +## a + +Assert __typeof__: + + user.should.be.a('object') + 'test'.should.be.a('string') + +## instanceof + +Assert __instanceof__: + + user.should.be.an.instanceof(User) + [].should.be.an.instanceof(Array) + +## above + +Assert numeric value above the given value: + + user.age.should.be.above(5) + user.age.should.not.be.above(100) + +## below + +Assert numeric value below the given value: + + user.age.should.be.below(100) + user.age.should.not.be.below(5) + +## match + +Assert regexp match: + + username.should.match(/^\w+$/) + +## length + +Assert _length_ property exists and has a value of the given number: + + user.pets.should.have.length(5) + user.pets.should.have.a.lengthOf(5) + +Aliases: _lengthOf_ + +## string + +Substring assertion: + + 'foobar'.should.include.string('foo') + 'foobar'.should.include.string('bar') + 'foobar'.should.not.include.string('baz') + +## property + +Assert property exists and has optional value: + + user.should.have.property('name') + user.should.have.property('age', 15) + user.should.not.have.property('rawr') + user.should.not.have.property('age', 0) + +## ownProperty + +Assert own property (on the immediate object): + + ({ foo: 'bar' }).should.have.ownProperty('foo') + +## contain + +Assert array value: + + [1,2,3].should.contain(3) + [1,2,3].should.contain(2) + [1,2,3].should.not.contain(4) + +## keys + +Assert own object keys, which must match _exactly_, +and will fail if you omit a key or two: + + var obj = { foo: 'bar', baz: 'raz' }; + obj.should.have.keys('foo', 'bar'); + obj.should.have.keys(['foo', 'bar']); + +using the _include_ modifier, we can check inclusion of a key, +but not fail when we omit a few: + + obj.should.include.keys('foo') + obj.should.include.keys('bar') + obj.should.not.include.keys('baz') + +## respondTo + +Assert that the given property is a function: + + user.should.respondTo('email') + +## Express example + +For example you can use should with the [Expresso TDD Framework](http://github.com/visionmedia/expresso) by simply including it: + + var lib = require('mylib') + , should = require('should'); + + module.exports = { + 'test .version': function(){ + lib.version.should.match(/^\d+\.\d+\.\d+$/); + } + }; + +## Running tests + +To run the tests for _should_ simple update your git submodules and run: + + $ make test + +## OMG IT EXTENDS OBJECT???!?!@ + +Yes, yes it does, with a single getter _should_, and no it wont break your code, because it does this **properly** with a non-enumerable property. + +## 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/NodeDrawing/node_modules/express/node_modules/qs/support/should/examples/runner.js b/NodeDrawing/node_modules/express/node_modules/qs/support/should/examples/runner.js new file mode 100644 index 0000000..9355955 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/examples/runner.js @@ -0,0 +1,53 @@ + +/** + * Module dependencies. + */ + +var should = require('../'); + +function test(name, fn){ + try { + fn(); + } catch (err) { + console.log(' \x1b[31m%s', name); + console.log(' %s\x1b[0m', err.stack); + return; + } + console.log(' √ \x1b[32m%s\x1b[0m', name); +} + +function Point(x, y) { + this.x = x; + this.y = y; + this.sub = function(other){ + return new Point( + this.x - other.x + , this.y - other.y); + } +} + +console.log(); + +test('new Point(x, y)', function(){ + var point = new Point(50, 100); + point.should.be.an.instanceof(Point); + point.should.have.property('x', 50); + point.should.have.property('y', 100); +}); + +test('Point#sub()', function(){ + var a = new Point(50, 100) + , b = new Point(20, 50); + a.sub(b).should.be.an.instanceof(Point); + a.sub(b).should.not.equal(a); + a.sub(b).should.not.equal(b); + a.sub(b).should.have.property('x', 30); + a.sub(b).should.have.property('y', 50); +}); + +test('Point#add()', function(){ + var point = new Point(50, 100); + point.should.respondTo('add'); +}); + +console.log(); \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/index.js b/NodeDrawing/node_modules/express/node_modules/qs/support/should/index.js new file mode 100644 index 0000000..6dbdbde --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/should'); \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/lib/eql.js b/NodeDrawing/node_modules/express/node_modules/qs/support/should/lib/eql.js new file mode 100644 index 0000000..31135e9 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/lib/eql.js @@ -0,0 +1,91 @@ + +// Taken from node's assert module, because it sucks +// and exposes next to nothing useful. + +module.exports = _deepEqual; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (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 _deepEqual(a, b); + } + try{ + var ka = Object.keys(a), + kb = Object.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 (!_deepEqual(a[key], b[key] )) + return false; + } + return true; +} diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/lib/should.js b/NodeDrawing/node_modules/express/node_modules/qs/support/should/lib/should.js new file mode 100644 index 0000000..f49475a --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/lib/should.js @@ -0,0 +1,548 @@ + +/*! + * Should + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var util = require('sys') + , assert = require('assert') + , AssertionError = assert.AssertionError + , eql = require('./eql') + , i = util.inspect; + +/** + * Expose assert as should. + * + * This allows you to do things like below + * without require()ing the assert module. + * + * should.equal(foo.bar, undefined); + * + */ + +exports = module.exports = assert; + +/** + * Library version. + */ + +exports.version = '0.0.4'; + +/** + * Expose api via `Object#should`. + * + * @api public + */ + +Object.defineProperty(Object.prototype, 'should', { + set: function(){}, + get: function(){ + return new Assertion(this); + } +}); + +/** + * Initialize a new `Assertion` with the given _obj_. + * + * @param {Mixed} obj + * @api private + */ + +var Assertion = exports.Assertion = function Assertion(obj) { + this.obj = obj; +}; + +/** + * Prototype. + */ + +Assertion.prototype = { + + /** + * HACK: prevents double require() from failing. + */ + + exports: exports, + + /** + * Assert _expr_ with the given _msg_ and _negatedMsg_. + * + * @param {Boolean} expr + * @param {String} msg + * @param {String} negatedMsg + * @api private + */ + + assert: function(expr, msg, negatedMsg){ + var msg = this.negate ? negatedMsg : msg + , ok = this.negate ? !expr : expr; + if (!ok) { + throw new AssertionError({ + message: msg + , stackStartFunction: this.assert + }); + } + }, + + /** + * Dummy getter. + * + * @api public + */ + + get an() { + return this; + }, + + /** + * Dummy getter. + * + * @api public + */ + + get and() { + return this; + }, + + /** + * Dummy getter. + * + * @api public + */ + + get be() { + return this; + }, + + /** + * Dummy getter. + * + * @api public + */ + + get have() { + return this; + }, + + /** + * Dummy getter. + * + * @api public + */ + + get with() { + return this; + }, + + /** + * Inclusion modifier. + * + * @api public + */ + + get include() { + this.includes = true; + return this; + }, + + /** + * Negation modifier. + * + * @api public + */ + + get not() { + this.negate = true; + return this; + }, + + /** + * Get object inspection string. + * + * @return {String} + * @api private + */ + + get inspect() { + return i(this.obj); + }, + + /** + * Assert instanceof `Arguments`. + * + * @api public + */ + + get arguments() { + this.assert( + '[object Arguments]' == Object.prototype.toString.call(this.obj) + , 'expected ' + this.inspect + ' to be arguments' + , 'expected ' + this.inspect + ' to not be arguments'); + return this; + }, + + /** + * Assert that an object is empty aka length of 0. + * + * @api public + */ + + get empty() { + this.obj.should.have.property('length'); + this.assert( + 0 === this.obj.length + , 'expected ' + this.inspect + ' to be empty' + , 'expected ' + this.inspect + ' not to be empty'); + return this; + }, + + /** + * Assert ok. + * + * @api public + */ + + get ok() { + this.assert( + this.obj + , 'expected ' + this.inspect + ' to be truthy' + , 'expected ' + this.inspect + ' to be falsey'); + return this; + }, + + /** + * Assert true. + * + * @api public + */ + + get true() { + this.assert( + true === this.obj + , 'expected ' + this.inspect + ' to be true' + , 'expected ' + this.inspect + ' not to be true'); + return this; + }, + + /** + * Assert false. + * + * @api public + */ + + get false() { + this.assert( + false === this.obj + , 'expected ' + this.inspect + ' to be false' + , 'expected ' + this.inspect + ' not to be false'); + return this; + }, + + /** + * Assert equal. + * + * @param {Mixed} val + * @api public + */ + + eql: function(val){ + this.assert( + eql(val, this.obj) + , 'expected ' + this.inspect + ' to equal ' + i(val) + , 'expected ' + this.inspect + ' to not equal ' + i(val)); + return this; + }, + + /** + * Assert strict equal. + * + * @param {Mixed} val + * @api public + */ + + equal: function(val){ + this.assert( + val === this.obj + , 'expected ' + this.inspect + ' to equal ' + i(val) + , 'expected ' + this.inspect + ' to not equal ' + i(val)); + return this; + }, + + /** + * Assert within start to finish (inclusive). + * + * @param {Number} start + * @param {Number} finish + * @api public + */ + + within: function(start, finish){ + var range = start + '..' + finish; + this.assert( + this.obj >= start && this.obj <= finish + , 'expected ' + this.inspect + ' to be within ' + range + , 'expected ' + this.inspect + ' to not be within ' + range); + return this; + }, + + /** + * Assert typeof. + * + * @api public + */ + + a: function(type){ + this.assert( + type == typeof this.obj + , 'expected ' + this.inspect + ' to be a ' + type + , 'expected ' + this.inspect + ' not to be a ' + type); + return this; + }, + + /** + * Assert instanceof. + * + * @api public + */ + + instanceof: function(constructor){ + var name = constructor.name; + this.assert( + this.obj instanceof constructor + , 'expected ' + this.inspect + ' to be an instance of ' + name + , 'expected ' + this.inspect + ' not to be an instance of ' + name); + return this; + }, + + /** + * Assert numeric value above _n_. + * + * @param {Number} n + * @api public + */ + + above: function(n){ + this.assert( + this.obj > n + , 'expected ' + this.inspect + ' to be above ' + n + , 'expected ' + this.inspect + ' to be below ' + n); + return this; + }, + + /** + * Assert numeric value below _n_. + * + * @param {Number} n + * @api public + */ + + below: function(n){ + this.assert( + this.obj < n + , 'expected ' + this.inspect + ' to be below ' + n + , 'expected ' + this.inspect + ' to be above ' + n); + return this; + }, + + /** + * Assert string value matches _regexp_. + * + * @param {RegExp} regexp + * @api public + */ + + match: function(regexp){ + this.assert( + regexp.exec(this.obj) + , 'expected ' + this.inspect + ' to match ' + regexp + , 'expected ' + this.inspect + ' not to match ' + regexp); + return this; + }, + + /** + * Assert property "length" exists and has value of _n_. + * + * @param {Number} n + * @api public + */ + + length: function(n){ + this.obj.should.have.property('length'); + var len = this.obj.length; + this.assert( + n == len + , 'expected ' + this.inspect + ' to have a length of ' + n + ' but got ' + len + , 'expected ' + this.inspect + ' to not have a length of ' + len); + return this; + }, + + /** + * Assert substring. + * + * @param {String} str + * @api public + */ + + string: function(str){ + this.obj.should.be.a('string'); + this.assert( + ~this.obj.indexOf(str) + , 'expected ' + this.inspect + ' to include ' + i(str) + , 'expected ' + this.inspect + ' to not include ' + i(str)); + return this; + }, + + /** + * Assert property _name_ exists, with optional _val_. + * + * @param {String} name + * @param {Mixed} val + * @api public + */ + + property: function(name, val){ + if (this.negate && undefined !== val) { + if (undefined === this.obj[name]) { + throw new Error(this.inspect + ' has no property ' + i(name)); + } + } else { + this.assert( + undefined !== this.obj[name] + , 'expected ' + this.inspect + ' to have a property ' + i(name) + , 'expected ' + this.inspect + ' to not have a property ' + i(name)); + } + + if (undefined !== val) { + this.assert( + val === this.obj[name] + , 'expected ' + this.inspect + ' to have a property ' + i(name) + + ' of ' + i(val) + ', but got ' + i(this.obj[name]) + , 'expected ' + this.inspect + ' to not have a property ' + i(name) + ' of ' + i(val)); + } + + this.obj = this.obj[name]; + return this; + }, + + /** + * Assert own property _name_ exists. + * + * @param {String} name + * @api public + */ + + ownProperty: function(name){ + this.assert( + this.obj.hasOwnProperty(name) + , 'expected ' + this.inspect + ' to have own property ' + i(name) + , 'expected ' + this.inspect + ' to not have own property ' + i(name)); + return this; + }, + + /** + * Assert that the array contains _obj_. + * + * @param {Mixed} obj + * @api public + */ + + contain: function(obj){ + this.obj.should.be.an.instanceof(Array); + this.assert( + ~this.obj.indexOf(obj) + , 'expected ' + this.inspect + ' to contain ' + i(obj) + , 'expected ' + this.inspect + ' to not contain ' + i(obj)); + return this; + }, + + /** + * Assert exact keys or inclusion of keys by using + * the `.include` modifier. + * + * @param {Array|String ...} keys + * @api public + */ + + keys: function(keys){ + var str + , ok = true; + + keys = keys instanceof Array + ? keys + : Array.prototype.slice.call(arguments); + + if (!keys.length) throw new Error('keys required'); + + var actual = Object.keys(this.obj) + , len = keys.length; + + // Inclusion + ok = keys.every(function(key){ + return ~actual.indexOf(key); + }); + + // Strict + if (!this.negate && !this.includes) { + ok = ok && keys.length == actual.length; + } + + // Key string + if (len > 1) { + keys = keys.map(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.includes ? 'include ' : 'have ') + str; + + // Assertion + this.assert( + ok + , 'expected ' + this.inspect + ' to ' + str + , 'expected ' + this.inspect + ' to not ' + str); + + return this; + }, + + /** + * Assert that _method_ is a function. + * + * @param {String} method + * @api public + */ + + respondTo: function(method){ + this.assert( + 'function' == typeof this.obj[method] + , 'expected ' + this.inspect + ' to respond to ' + method + '()' + , 'expected ' + this.inspect + ' to not respond to ' + method + '()'); + return this; + } +}; + +/** + * Aliases. + */ + +(function alias(name, as){ + Assertion.prototype[as] = Assertion.prototype[name]; + return alias; +}) +('length', 'lengthOf') +('keys', 'key') +('ownProperty', 'haveOwnProperty') +('above', 'greaterThan') +('below', 'lessThan'); diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/package.json b/NodeDrawing/node_modules/express/node_modules/qs/support/should/package.json new file mode 100644 index 0000000..413e437 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/package.json @@ -0,0 +1,8 @@ +{ "name": "should" + , "description": "test framework agnostic BDD-style assertions" + , "version": "0.0.4" + , "author": "TJ Holowaychuk " + , "keywords": ["test", "bdd", "assert"] + , "main": "./lib/should.js" + , "engines": { "node": ">= 0.2.0" } +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/support/should/test/should.test.js b/NodeDrawing/node_modules/express/node_modules/qs/support/should/test/should.test.js new file mode 100644 index 0000000..4f39f67 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/support/should/test/should.test.js @@ -0,0 +1,358 @@ + +/** + * Module dependencies. + */ + +var should = require('should'); + +function err(fn, msg) { + try { + fn(); + should.fail('expected an error'); + } catch (err) { + should.equal(msg, err.message); + } +} + +module.exports = { + 'test .version': function(){ + should.version.should.match(/^\d+\.\d+\.\d+$/); + }, + + 'test double require': function(){ + require('should').should.equal(should); + }, + + 'test assertion': function(){ + 'test'.should.be.a.string; + should.equal('foo', 'foo'); + }, + + 'test true': function(){ + true.should.be.true; + false.should.not.be.true; + (1).should.not.be.true; + + err(function(){ + 'test'.should.be.true; + }, "expected 'test' to be true") + }, + + 'test ok': function(){ + true.should.be.ok; + false.should.not.be.ok; + (1).should.be.ok; + (0).should.not.be.ok; + + err(function(){ + ''.should.be.ok; + }, "expected '' to be truthy"); + + err(function(){ + 'test'.should.not.be.ok; + }, "expected 'test' to be falsey"); + }, + + 'test false': function(){ + false.should.be.false; + true.should.not.be.false; + (0).should.not.be.false; + + err(function(){ + ''.should.be.false; + }, "expected '' to be false") + }, + + 'test arguments': function(){ + var args = (function(){ return arguments; })(1,2,3); + args.should.be.arguments; + [].should.not.be.arguments; + }, + + 'test .equal()': function(){ + var foo; + should.equal(undefined, foo); + }, + + 'test typeof': function(){ + 'test'.should.be.a('string'); + + err(function(){ + 'test'.should.not.be.a('string'); + }, "expected 'test' not to be a string"); + + (5).should.be.a('number'); + + err(function(){ + (5).should.not.be.a('number'); + }, "expected 5 not to be a number"); + }, + + 'test instanceof': function(){ + function Foo(){} + new Foo().should.be.an.instanceof(Foo); + + err(function(){ + (3).should.an.instanceof(Foo); + }, "expected 3 to be an instance of Foo"); + }, + + 'test within(start, finish)': function(){ + (5).should.be.within(5, 10); + (5).should.be.within(3,6); + (5).should.be.within(3,5); + (5).should.not.be.within(1,3); + + err(function(){ + (5).should.not.be.within(4,6); + }, "expected 5 to not be within 4..6"); + + err(function(){ + (10).should.be.within(50,100); + }, "expected 10 to be within 50..100"); + }, + + 'test above(n)': function(){ + (5).should.be.above(2); + (5).should.be.greaterThan(2); + (5).should.not.be.above(5); + (5).should.not.be.above(6); + + err(function(){ + (5).should.be.above(6); + }, "expected 5 to be above 6"); + + err(function(){ + (10).should.not.be.above(6); + }, "expected 10 to be below 6"); + }, + + 'test match(regexp)': function(){ + 'foobar'.should.match(/^foo/) + 'foobar'.should.not.match(/^bar/) + + err(function(){ + 'foobar'.should.match(/^bar/i) + }, "expected 'foobar' to match /^bar/i"); + + err(function(){ + 'foobar'.should.not.match(/^foo/i) + }, "expected 'foobar' not to match /^foo/i"); + }, + + 'test length(n)': function(){ + 'test'.should.have.length(4); + 'test'.should.not.have.length(3); + [1,2,3].should.have.length(3); + + err(function(){ + (4).should.have.length(3); + }, 'expected 4 to have a property \'length\''); + + err(function(){ + 'asd'.should.not.have.length(3); + }, "expected 'asd' to not have a length of 3"); + }, + + 'test eql(val)': function(){ + 'test'.should.eql('test'); + ({ foo: 'bar' }).should.eql({ foo: 'bar' }); + (1).should.eql(1); + '4'.should.eql(4); + + err(function(){ + (4).should.eql(3); + }, 'expected 4 to equal 3'); + }, + + 'test equal(val)': function(){ + 'test'.should.equal('test'); + (1).should.equal(1); + + err(function(){ + (4).should.equal(3); + }, 'expected 4 to equal 3'); + + err(function(){ + '4'.should.equal(4); + }, "expected '4' to equal 4"); + }, + + 'test empty': function(){ + ''.should.be.empty; + [].should.be.empty; + ({ length: 0 }).should.be.empty; + + err(function(){ + ({}).should.be.empty; + }, 'expected {} to have a property \'length\''); + + err(function(){ + 'asd'.should.be.empty; + }, "expected 'asd' to be empty"); + + err(function(){ + ''.should.not.be.empty; + }, "expected '' not to be empty"); + }, + + 'test property(name)': function(){ + 'test'.should.have.property('length'); + (4).should.not.have.property('length'); + + err(function(){ + 'asd'.should.have.property('foo'); + }, "expected 'asd' to have a property 'foo'"); + }, + + 'test property(name, val)': function(){ + 'test'.should.have.property('length', 4); + 'asd'.should.have.property('constructor', String); + + err(function(){ + 'asd'.should.have.property('length', 4); + }, "expected 'asd' to have a property 'length' of 4, but got 3"); + + err(function(){ + 'asd'.should.not.have.property('length', 3); + }, "expected 'asd' to not have a property 'length' of 3"); + + err(function(){ + 'asd'.should.not.have.property('foo', 3); + }, "'asd' has no property 'foo'"); + + err(function(){ + 'asd'.should.have.property('constructor', Number); + }, "expected 'asd' to have a property 'constructor' of [Function: Number], but got [Function: String]"); + }, + + 'test ownProperty(name)': function(){ + 'test'.should.have.ownProperty('length'); + 'test'.should.haveOwnProperty('length'); + ({ length: 12 }).should.have.ownProperty('length'); + + err(function(){ + ({ length: 12 }).should.not.have.ownProperty('length'); + }, "expected { length: 12 } to not have own property 'length'"); + }, + + 'test string()': function(){ + 'foobar'.should.include.string('bar'); + 'foobar'.should.include.string('foo'); + 'foobar'.should.not.include.string('baz'); + + err(function(){ + (3).should.include.string('baz'); + }, "expected 3 to be a string"); + + err(function(){ + 'foobar'.should.include.string('baz'); + }, "expected 'foobar' to include 'baz'"); + + err(function(){ + 'foobar'.should.not.include.string('bar'); + }, "expected 'foobar' to not include 'bar'"); + }, + + 'test contain()': function(){ + ['foo', 'bar'].should.contain('foo'); + ['foo', 'bar'].should.contain('foo'); + ['foo', 'bar'].should.contain('bar'); + [1,2].should.contain(1); + ['foo', 'bar'].should.not.contain('baz'); + ['foo', 'bar'].should.not.contain(1); + + err(function(){ + ['foo'].should.contain('bar'); + }, "expected [ 'foo' ] to contain 'bar'"); + + err(function(){ + ['bar', 'foo'].should.not.contain('foo'); + }, "expected [ 'bar', 'foo' ] to not contain 'foo'"); + }, + + 'test keys(array)': function(){ + ({ foo: 1 }).should.have.keys(['foo']); + ({ foo: 1, bar: 2 }).should.have.keys(['foo', 'bar']); + ({ foo: 1, bar: 2 }).should.have.keys('foo', 'bar'); + ({ foo: 1, bar: 2, baz: 3 }).should.include.keys('foo', 'bar'); + ({ foo: 1, bar: 2, baz: 3 }).should.include.keys('bar', 'foo'); + ({ foo: 1, bar: 2, baz: 3 }).should.include.keys('baz'); + + ({ foo: 1, bar: 2 }).should.include.keys('foo'); + ({ foo: 1, bar: 2 }).should.include.keys('bar', 'foo'); + ({ foo: 1, bar: 2 }).should.include.keys(['foo']); + ({ foo: 1, bar: 2 }).should.include.keys(['bar']); + ({ foo: 1, bar: 2 }).should.include.keys(['bar', 'foo']); + + ({ foo: 1, bar: 2 }).should.not.have.keys('baz'); + ({ foo: 1, bar: 2 }).should.not.have.keys('foo', 'baz'); + ({ foo: 1, bar: 2 }).should.not.include.keys('baz'); + ({ foo: 1, bar: 2 }).should.not.include.keys('foo', 'baz'); + ({ foo: 1, bar: 2 }).should.not.include.keys('baz', 'foo'); + + err(function(){ + ({ foo: 1 }).should.have.keys(); + }, "keys required"); + + err(function(){ + ({ foo: 1 }).should.have.keys([]); + }, "keys required"); + + err(function(){ + ({ foo: 1 }).should.not.have.keys([]); + }, "keys required"); + + err(function(){ + ({ foo: 1 }).should.include.keys([]); + }, "keys required"); + + err(function(){ + ({ foo: 1 }).should.have.keys(['bar']); + }, "expected { foo: 1 } to have key 'bar'"); + + err(function(){ + ({ foo: 1 }).should.have.keys(['bar', 'baz']); + }, "expected { foo: 1 } to have keys 'bar', and 'baz'"); + + err(function(){ + ({ foo: 1 }).should.have.keys(['foo', 'bar', 'baz']); + }, "expected { foo: 1 } to have keys 'foo', 'bar', and 'baz'"); + + err(function(){ + ({ foo: 1 }).should.not.have.keys(['foo']); + }, "expected { foo: 1 } to not have key 'foo'"); + + err(function(){ + ({ foo: 1 }).should.not.have.keys(['foo']); + }, "expected { foo: 1 } to not have key 'foo'"); + + err(function(){ + ({ foo: 1, bar: 2 }).should.not.have.keys(['foo', 'bar']); + }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'"); + + err(function(){ + ({ foo: 1 }).should.not.include.keys(['foo']); + }, "expected { foo: 1 } to not include key 'foo'"); + + err(function(){ + ({ foo: 1 }).should.include.keys('foo', 'bar'); + }, "expected { foo: 1 } to include keys 'foo', and 'bar'"); + }, + + 'test respondTo(method)': function(){ + 'test'.should.respondTo('toString'); + 'test'.should.not.respondTo('toBuffer'); + }, + + 'test chaining': function(){ + var user = { name: 'tj', pets: ['tobi', 'loki', 'jane', 'bandit'] }; + user.should.have.property('pets').with.lengthOf(4); + + err(function(){ + user.should.have.property('pets').with.lengthOf(5); + }, "expected [ 'tobi', 'loki', 'jane', 'bandit' ] to have a length of 5 but got 4"); + + user.should.be.a('object').and.have.property('name', 'tj'); + } +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/node_modules/qs/test/parse.test.js b/NodeDrawing/node_modules/express/node_modules/qs/test/parse.test.js new file mode 100644 index 0000000..4e7d730 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/test/parse.test.js @@ -0,0 +1,156 @@ + +/** + * Module dependencies. + */ + +var qs = require('../') + , should = require('should'); + +module.exports = { + 'test basics': function(){ + qs.parse('0=foo').should.eql({ '0': 'foo' }); + + qs.parse('foo=c++') + .should.eql({ foo: 'c ' }); + + qs.parse('a[>=]=23') + .should.eql({ a: { '>=': '23' }}); + + qs.parse('a[<=>]==23') + .should.eql({ a: { '<=>': '=23' }}); + + qs.parse('a[==]=23') + .should.eql({ a: { '==': '23' }}); + + qs.parse('foo') + .should.eql({ foo: '' }); + + qs.parse('foo=bar') + .should.eql({ foo: 'bar' }); + + qs.parse('foo%3Dbar=baz') + .should.eql({ foo: 'bar=baz' }); + + qs.parse(' foo = bar = baz ') + .should.eql({ ' foo ': ' bar = baz ' }); + + qs.parse('foo=bar=baz') + .should.eql({ foo: 'bar=baz' }); + + qs.parse('foo=bar&bar=baz') + .should.eql({ foo: 'bar', bar: 'baz' }); + + qs.parse('foo=bar&baz') + .should.eql({ foo: 'bar', baz: '' }); + + qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World') + .should.eql({ + cht: 'p3' + , chd: 't:60,40' + , chs: '250x100' + , chl: 'Hello|World' + }); + }, + + 'test nesting': function(){ + qs.parse('ops[>=]=25') + .should.eql({ ops: { '>=': '25' }}); + + qs.parse('user[name]=tj') + .should.eql({ user: { name: 'tj' }}); + + qs.parse('user[name][first]=tj&user[name][last]=holowaychuk') + .should.eql({ user: { name: { first: 'tj', last: 'holowaychuk' }}}); + }, + + 'test escaping': function(){ + qs.parse('foo=foo%20bar') + .should.eql({ foo: 'foo bar' }); + }, + + 'test arrays': function(){ + qs.parse('images[]') + .should.eql({ images: [] }); + + qs.parse('user[]=tj') + .should.eql({ user: ['tj'] }); + + qs.parse('user[]=tj&user[]=tobi&user[]=jane') + .should.eql({ user: ['tj', 'tobi', 'jane'] }); + + qs.parse('user[names][]=tj&user[names][]=tyler') + .should.eql({ user: { names: ['tj', 'tyler'] }}); + + qs.parse('user[names][]=tj&user[names][]=tyler&user[email]=tj@vision-media.ca') + .should.eql({ user: { names: ['tj', 'tyler'], email: 'tj@vision-media.ca' }}); + + qs.parse('items=a&items=b') + .should.eql({ items: ['a', 'b'] }); + + qs.parse('user[names]=tj&user[names]=holowaychuk&user[names]=TJ') + .should.eql({ user: { names: ['tj', 'holowaychuk', 'TJ'] }}); + + qs.parse('user[name][first]=tj&user[name][first]=TJ') + .should.eql({ user: { name: { first: ['tj', 'TJ'] }}}); + }, + + 'test right-hand brackets': function(){ + qs.parse('pets=["tobi"]') + .should.eql({ pets: '["tobi"]' }); + + qs.parse('operators=[">=", "<="]') + .should.eql({ operators: '[">=", "<="]' }); + + qs.parse('op[>=]=[1,2,3]') + .should.eql({ op: { '>=': '[1,2,3]' }}); + + qs.parse('op[>=]=[1,2,3]&op[=]=[[[[1]]]]') + .should.eql({ op: { '>=': '[1,2,3]', '=': '[[[[1]]]]' }}); + }, + + 'test duplicates': function(){ + qs.parse('items=bar&items=baz&items=raz') + .should.eql({ items: ['bar', 'baz', 'raz'] }); + }, + + 'test empty': function(){ + qs.parse('').should.eql({}); + qs.parse(undefined).should.eql({}); + qs.parse(null).should.eql({}); + }, + + 'test arrays with indexes': function(){ + qs.parse('foo[0]=bar&foo[1]=baz').should.eql({ foo: ['bar', 'baz'] }); + qs.parse('foo[1]=bar&foo[0]=baz').should.eql({ foo: ['baz', 'bar'] }); + qs.parse('foo[base64]=RAWR').should.eql({ foo: { base64: 'RAWR' }}); + qs.parse('foo[64base]=RAWR').should.eql({ foo: { '64base': 'RAWR' }}); + }, + + 'test arrays becoming objects': function(){ + qs.parse('foo[0]=bar&foo[bad]=baz').should.eql({ foo: { 0: "bar", bad: "baz" }}); + qs.parse('foo[bad]=baz&foo[0]=bar').should.eql({ foo: { 0: "bar", bad: "baz" }}); + }, + + 'test bleed-through of Array native properties/methods': function(){ + Array.prototype.protoProperty = true; + Array.prototype.protoFunction = function () {}; + qs.parse('foo=bar').should.eql({ foo: 'bar' }); + }, + + 'test malformed uri': function(){ + qs.parse('{%:%}').should.eql({ '{%:%}': '' }); + qs.parse('foo=%:%}').should.eql({ 'foo': '%:%}' }); + } + + // 'test complex': function(){ + // qs.parse('users[][name][first]=tj&users[foo]=bar') + // .should.eql({ + // users: [ { name: 'tj' }, { name: 'tobi' }, { foo: 'bar' }] + // }); + // + // qs.parse('users[][name][first]=tj&users[][name][first]=tobi') + // .should.eql({ + // users: [ { name: 'tj' }, { name: 'tobi' }] + // }); + // } +}; diff --git a/NodeDrawing/node_modules/express/node_modules/qs/test/stringify.test.js b/NodeDrawing/node_modules/express/node_modules/qs/test/stringify.test.js new file mode 100644 index 0000000..5f688d8 --- /dev/null +++ b/NodeDrawing/node_modules/express/node_modules/qs/test/stringify.test.js @@ -0,0 +1,95 @@ + +/** + * Module dependencies. + */ + +var qs = require('../') + , should = require('should') + , query_string_identities = { + 'basics': [ + {query_string: 'foo=bar', parsed: {'foo' : 'bar'}}, + {query_string: 'foo=%22bar%22', parsed: {'foo' : '\"bar\"'}}, + {query_string: 'foo=', parsed: {'foo': ''}}, + {query_string: 'foo=1&bar=2', parsed: {'foo' : '1', 'bar' : '2'}}, + {query_string: 'my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F', parsed: {'my weird field': "q1!2\"'w$5&7/z8)?"}}, + {query_string: 'foo%3Dbaz=bar', parsed: {'foo=baz': 'bar'}}, + {query_string: 'foo=bar&bar=baz', parsed: {foo: 'bar', bar: 'baz'}} + ], + 'escaping': [ + {query_string: 'foo=foo%20bar', parsed: {foo: 'foo bar'}}, + {query_string: 'cht=p3&chd=t%3A60%2C40&chs=250x100&chl=Hello%7CWorld', parsed: { + cht: 'p3' + , chd: 't:60,40' + , chs: '250x100' + , chl: 'Hello|World' + }} + ], + 'nested': [ + {query_string: 'foo[]=bar&foo[]=quux', parsed: {'foo' : ['bar', 'quux']}}, + {query_string: 'foo[]=bar', parsed: {foo: ['bar']}}, + {query_string: 'foo[]=1&foo[]=2', parsed: {'foo' : ['1', '2']}}, + {query_string: 'foo=bar&baz[]=1&baz[]=2&baz[]=3', parsed: {'foo' : 'bar', 'baz' : ['1', '2', '3']}}, + {query_string: 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3', parsed: {'foo' : ['bar'], 'baz' : ['1', '2', '3']}}, + {query_string: 'x[y][z]=1', parsed: {'x' : {'y' : {'z' : '1'}}}}, + {query_string: 'x[y][z][]=1', parsed: {'x' : {'y' : {'z' : ['1']}}}}, + {query_string: 'x[y][z]=2', parsed: {'x' : {'y' : {'z' : '2'}}}}, + {query_string: 'x[y][z][]=1&x[y][z][]=2', parsed: {'x' : {'y' : {'z' : ['1', '2']}}}}, + {query_string: 'x[y][][z]=1', parsed: {'x' : {'y' : [{'z' : '1'}]}}}, + {query_string: 'x[y][][z][]=1', parsed: {'x' : {'y' : [{'z' : ['1']}]}}}, + {query_string: 'x[y][][z]=1&x[y][][w]=2', parsed: {'x' : {'y' : [{'z' : '1', 'w' : '2'}]}}}, + {query_string: 'x[y][][v][w]=1', parsed: {'x' : {'y' : [{'v' : {'w' : '1'}}]}}}, + {query_string: 'x[y][][z]=1&x[y][][v][w]=2', parsed: {'x' : {'y' : [{'z' : '1', 'v' : {'w' : '2'}}]}}}, + {query_string: 'x[y][][z]=1&x[y][][z]=2', parsed: {'x' : {'y' : [{'z' : '1'}, {'z' : '2'}]}}}, + {query_string: 'x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3', parsed: {'x' : {'y' : [{'z' : '1', 'w' : 'a'}, {'z' : '2', 'w' : '3'}]}}}, + {query_string: 'user[name][first]=tj&user[name][last]=holowaychuk', parsed: { user: { name: { first: 'tj', last: 'holowaychuk' }}}} + ], + 'errors': [ + { parsed: 'foo=bar', message: 'stringify expects an object' }, + { parsed: ['foo', 'bar'], message: 'stringify expects an object' } + ] + }; + + +// Assert error +function err(fn, msg){ + var err; + try { + fn(); + } catch (e) { + should.equal(e.message, msg); + return; + } + throw new Error('no exception thrown, expected "' + msg + '"'); +} + +function test(type) { + var str, obj; + for (var i = 0; i < query_string_identities[type].length; i++) { + str = query_string_identities[type][i].query_string; + obj = query_string_identities[type][i].parsed; + qs.stringify(obj).should.eql(str); + } +} + +module.exports = { + 'test basics': function() { + test('basics'); + }, + + 'test escaping': function() { + test('escaping'); + }, + + 'test nested': function() { + test('nested'); + }, + + 'test errors': function() { + var parsed, message; + for (var i = 0; i < query_string_identities['errors'].length; i++) { + message = query_string_identities['errors'][i].message; + parsed = query_string_identities['errors'][i].parsed; + err(function(){ qs.stringify(parsed) }, message); + } + } +}; \ No newline at end of file diff --git a/NodeDrawing/node_modules/express/package.json b/NodeDrawing/node_modules/express/package.json new file mode 100644 index 0000000..5efdbcb --- /dev/null +++ b/NodeDrawing/node_modules/express/package.json @@ -0,0 +1,38 @@ +{ + "name": "express", + "description": "Sinatra inspired web development framework", + "version": "2.3.12", + "author": "TJ Holowaychuk ", + "contributors": [ + { "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" }, + { "name": "Aaron Heckmann", "email": "aaron.heckmann+github@gmail.com" }, + { "name": "Ciaran Jessup", "email": "ciaranj@gmail.com" }, + { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" } + ], + "dependencies": { + "connect": ">= 1.5.1 < 2.0.0", + "mime": ">= 0.0.1", + "qs": ">= 0.0.6" + }, + "devDependencies": { + "connect-form": "0.2.1", + "ejs": "0.4.2", + "expresso": "0.7.2", + "hamljs": "0.5.1", + "jade": "0.11.0", + "stylus": "0.13.0", + "should": "0.2.1", + "express-messages": "0.0.2", + "node-markdown": ">= 0.0.1", + "connect-redis": ">= 0.0.1" + }, + "keywords": ["framework", "sinatra", "web", "rest", "restful"], + "repository": "git://github.com/visionmedia/express", + "main": "index", + "bin": { "express": "./bin/express" }, + "scripts": { + "test": "make test", + "prepublish" : "npm prune" + }, + "engines": { "node": ">= 0.4.1 < 0.5.0" } +} \ No newline at end of file diff --git a/NodeDrawing/node_modules/socket.io/.gitignore b/NodeDrawing/node_modules/socket.io/.gitignore new file mode 100644 index 0000000..43378d0 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +node_modules diff --git a/NodeDrawing/node_modules/socket.io/.npmignore b/NodeDrawing/node_modules/socket.io/.npmignore new file mode 100644 index 0000000..39e9864 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/.npmignore @@ -0,0 +1,3 @@ +support +test +examples diff --git a/NodeDrawing/node_modules/socket.io/History.md b/NodeDrawing/node_modules/socket.io/History.md new file mode 100644 index 0000000..3bccc93 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/History.md @@ -0,0 +1,89 @@ + +0.7.8 / 2011-08-08 +================== + + * Changed; make sure sio#listen passes options to both HTTP server and socket.io manager. + * Added docs for sio#listen. + * Added options parameter support for Manager constructor. + * Added memory leaks tests and test-leaks Makefile task. + * Removed auto npm-linking from make test. + * Make sure that you can disable heartbeats. [3rd-Eden] + * Fixed rooms memory leak [3rd-Eden] + * Send response once we got all POST data, not immediately [Pita] + * Fixed onLeave behavior with missing clientsk [3rd-Eden] + * Prevent duplicate references in rooms. + * Added alias for `to` to `in` and `in` to `to`. + * Fixed roomClients definition. + * Removed dependency on redis for installation without npm [3rd-Eden] + * Expose path and querystring in handshakeData [3rd-Eden] + +0.7.7 / 2011-07-12 +================== + + * Fixed double dispatch handling with emit to closed clients. + * Added test for emitting to closed clients to prevent regression. + * Fixed race condition in redis test. + * Changed Transport#end instrumentation. + * Leveraged $emit instead of emit internally. + * Made tests faster. + * Fixed double disconnect events. + * Fixed disconnect logic + * Simplified remote events handling in Socket. + * Increased testcase timeout. + * Fixed unknown room emitting (GH-291). [3rd-Eden] + * Fixed `address` in handshakeData. [3rd-Eden] + * Removed transports definition in chat example. + * Fixed room cleanup + * Fixed; make sure the client is cleaned up after booting. + * Make sure to mark the client as non-open if the connection is closed. + * Removed unneeded `buffer` declarations. + * Fixed; make sure to clear socket handlers and subscriptions upon transport close. + +0.7.6 / 2011-06-30 +================== + + * Fixed general dispatching when a client has closed. + +0.7.5 / 2011-06-30 +================== + + * Fixed dispatching to clients that are disconnected. + +0.7.4 / 2011-06-30 +================== + + * Fixed; only clear handlers if they were set. [level09] + +0.7.3 / 2011-06-30 +================== + + * Exposed handshake data to clients. + * Refactored dispatcher interface. + * Changed; Moved id generation method into the manager. + * Added sub-namespace authorization. [3rd-Eden] + * Changed; normalized SocketNamespace local eventing [dvv] + * Changed; Use packet.reason or default to 'packet' [3rd-Eden] + * Changed console.error to console.log. + * Fixed; bind both servers at the same time do that the test never times out. + * Added 304 support. + * Removed `Transport#name` for abstract interface. + * Changed; lazily require http and https module only when needed. [3rd-Eden] + +0.7.2 / 2011-06-22 +================== + + * Make sure to write a packet (of type `noop`) when closing a poll. + This solves a problem with cross-domain requests being flagged as aborted and + reconnection being triggered. + * Added `noop` message type. + +0.7.1 / 2011-06-21 +================== + + * Fixed cross-domain XHR. + * Added CORS test to xhr-polling suite. + +0.7.0 / 2010-06-21 +================== + + * http://socket.io/announcement.html diff --git a/NodeDrawing/node_modules/socket.io/Makefile b/NodeDrawing/node_modules/socket.io/Makefile new file mode 100644 index 0000000..7981705 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/Makefile @@ -0,0 +1,22 @@ + +ALL_TESTS = $(shell find test/ -name '*.test.js') + +run-tests: + @./node_modules/.bin/expresso \ + -t 3000 \ + -I support \ + -I lib \ + --serial \ + $(TESTFLAGS) \ + $(TESTS) + +test: + @$(MAKE) TESTS="$(ALL_TESTS)" run-tests + +test-cov: + @TESTFLAGS=--cov $(MAKE) test + +test-leaks: + @ls test/leaks/* | xargs node --expose_debug_as=debug --expose_gc + +.PHONY: test diff --git a/NodeDrawing/node_modules/socket.io/Readme.md b/NodeDrawing/node_modules/socket.io/Readme.md new file mode 100644 index 0000000..875e5df --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/Readme.md @@ -0,0 +1,343 @@ +# Socket.IO + +Socket.IO is a Node.JS project that makes WebSockets and realtime possible in +all browsers. It also enhances WebSockets by providing built-in multiplexing, +horizontal scalability, automatic JSON encoding/decoding, and more. + +## How to Install + + npm install socket.io + +## How to use + +First, require `socket.io`: + +```js +var io = require('socket.io'); +``` + +Next, attach it to a HTTP/HTTPS server. If you're using the fantastic `express` +web framework: + +```js +var app = express.createServer() + , io = io.listen(app); + +app.listen(80); + +io.sockets.on('connection', function (socket) { + socket.emit('news', { hello: 'world' }); + socket.on('my other event', function (data) { + console.log(data); + }); +}); +``` + +Finally, load it from the client side code: + +```html + + +``` + +For more thorough examples, look at the `examples/` directory. + +## Short recipes + +### Sending and receiving events. + +Socket.IO allows you to emit and receive custom events. +Besides `connect`, `message` and `disconnect`, you can emit custom events: + +```js +// note, io.listen() will create a http server for you +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + io.sockets.emit('this', { will: 'be received by everyone'); + + socket.on('private message', function (from, msg) { + console.log('I received a private message by ', from, ' saying ', msg); + }); + + socket.on('disconnect', function () { + sockets.emit('user disconnected'); + }); +}); +``` + +### Storing data associated to a client + +Sometimes it's necessary to store data associated with a client that's +necessary for the duration of the session. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('set nickname', function (name) { + socket.set('nickname', name, function () { socket.emit('ready'); }); + }); + + socket.on('msg', function () { + socket.get('nickname', function (err, name) { + console.log('Chat message by ', name); + }); + }); +}); +``` + +#### Client side + +```html + +``` + +### Restricting yourself to a namespace + +If you have control over all the messages and events emitted for a particular +application, using the default `/` namespace works. + +If you want to leverage 3rd-party code, or produce code to share with others, +socket.io provides a way of namespacing a `socket`. + +This has the benefit of `multiplexing` a single connection. Instead of +socket.io using two `WebSocket` connections, it'll use one. + +The following example defines a socket that listens on '/chat' and one for +'/news': + +#### Server side + +```js +var io = require('socket.io').listen(80); + +var chat = io + .of('/chat'); + .on('connection', function (socket) { + socket.emit('a message', { that: 'only', '/chat': 'will get' }); + chat.emit('a message', { everyone: 'in', '/chat': 'will get' }); + }); + +var news = io + .of('/news'); + .on('connection', function (socket) { + socket.emit('item', { news: 'item' }); + }); +``` + +#### Client side: + +```html + +``` + +### Sending volatile messages. + +Sometimes certain messages can be dropped. Let's say you have an app that +shows realtime tweets for the keyword `bieber`. + +If a certain client is not ready to receive messages (because of network slowness +or other issues, or because he's connected through long polling and is in the +middle of a request-response cycle), if he doesn't receive ALL the tweets related +to bieber your application won't suffer. + +In that case, you might want to send those messages as volatile messages. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + var tweets = setInterval(function () { + getBieberTweet(function (tweet) { + socket.volatile.emit('bieber tweet', tweet); + }); + }, 100); + + socket.on('disconnect', function () { + clearInterval(tweets); + }); +}); +``` + +#### Client side + +In the client side, messages are received the same way whether they're volatile +or not. + +### Getting acknowledgements + +Sometimes, you might want to get a callback when the client confirmed the message +reception. + +To do this, simply pass a function as the last parameter of `.send` or `.emit`. +What's more, when you use `.emit`, the acknowledgement is done by you, which +means you can also pass data along: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('ferret', function (name, fn) { + fn('woot'); + }); +}); +``` + +#### Client side + +```html + +``` + +### Broadcasting messages + +To broadcast, simply add a `broadcast` flag to `emit` and `send` method calls. +Broadcasting means sending a message to everyone else except for the socket +that starts it. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.broadcast.emit('user connected'); + socket.broadcast.json.send({ a: 'message' }); +}); +``` + +### Rooms + +Sometimes you want to put certain sockets in the same room, so that it's easy +to broadcast to all of them together. + +Think of this as built-in channels for sockets. Sockets `join` and `leave` +rooms in each socket. + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.join('justin bieber fans'); + socket.broadcast.to('justin bieber fans').emit('new fan'); + io.sockets.in('rammstein fans').emit('new non-fan'); +}); +``` + +### Using it just as a cross-browser WebSocket + +If you just want the WebSocket semantics, you can do that too. +Simply leverage `send` and listen on the `message` event: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.sockets.on('connection', function (socket) { + socket.on('message', function () { }); + socket.on('disconnect', function () { }); +}); +``` + +#### Client side + +```html + +``` + +### Changing configuration + +Configuration in socket.io is TJ-style: + +#### Server side + +```js +var io = require('socket.io').listen(80); + +io.configure(function () { + io.set('transports', ['websocket', 'flashsocket', 'xhr-polling']); +}); + +io.configure('development', function () { + io.set('transports', ['websocket', 'xhr-polling']); + io.enable('log'); +}); +``` + +## License + +(The MIT License) + +Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.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/NodeDrawing/node_modules/socket.io/examples/chat/app.js b/NodeDrawing/node_modules/socket.io/examples/chat/app.js new file mode 100644 index 0000000..23f09f0 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/chat/app.js @@ -0,0 +1,87 @@ + +/** + * Bootstrap app. + */ + +require.paths.unshift(__dirname + '/../../lib/'); + +/** + * Module dependencies. + */ + +var express = require('express') + , stylus = require('stylus') + , nib = require('nib') + , sio = require('socket.io'); + +/** + * App. + */ + +var app = express.createServer(); + +/** + * App configuration. + */ + +app.configure(function () { + app.use(stylus.middleware({ src: __dirname + '/public', compile: compile })) + app.use(express.static(__dirname + '/public')); + app.set('views', __dirname); + app.set('view engine', 'jade'); + + function compile (str, path) { + return stylus(str) + .set('filename', path) + .use(nib()); + }; +}); + +/** + * App routes. + */ + +app.get('/', function (req, res) { + res.render('index', { layout: false }); +}); + +/** + * App listen. + */ + +app.listen(3000, function () { + var addr = app.address(); + console.log(' app listening on http://' + addr.address + ':' + addr.port); +}); + +/** + * Socket.IO server (single process only) + */ + +var io = sio.listen(app) + , nicknames = {}; + +io.sockets.on('connection', function (socket) { + socket.on('user message', function (msg) { + socket.broadcast.emit('user message', socket.nickname, msg); + }); + + socket.on('nickname', function (nick, fn) { + if (nicknames[nick]) { + fn(true); + } else { + fn(false); + nicknames[nick] = socket.nickname = nick; + socket.broadcast.emit('announcement', nick + ' connected'); + io.sockets.emit('nicknames', nicknames); + } + }); + + socket.on('disconnect', function () { + if (!socket.nickname) return; + + delete nicknames[socket.nickname]; + socket.broadcast.emit('announcement', socket.nickname + ' disconnected'); + socket.broadcast.emit('nicknames', nicknames); + }); +}); diff --git a/NodeDrawing/node_modules/socket.io/examples/chat/index.jade b/NodeDrawing/node_modules/socket.io/examples/chat/index.jade new file mode 100644 index 0000000..0633d8b --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/chat/index.jade @@ -0,0 +1,83 @@ +doctype 5 +html + head + link(href='/stylesheets/style.css', rel='stylesheet') + script(src='http://code.jquery.com/jquery-1.6.1.min.js') + script(src='/socket.io/socket.io.js') + script + // socket.io specific code + var socket = io.connect(); + + socket.on('connect', function () { + $('#chat').addClass('connected'); + }); + + socket.on('announcement', function (msg) { + $('#lines').append($('

    ').append($('').text(msg))); + }); + + socket.on('nicknames', function (nicknames) { + $('#nicknames').empty().append($('Online: ')); + for (var i in nicknames) { + $('#nicknames').append($('').text(nicknames[i])); + } + }); + + socket.on('user message', message); + socket.on('reconnect', function () { + $('#lines').remove(); + message('System', 'Reconnected to the server'); + }); + + socket.on('reconnecting', function () { + message('System', 'Attempting to re-connect to the server'); + }); + + socket.on('error', function (e) { + message('System', e ? e : 'A unknown error occurred'); + }); + + function message (from, msg) { + $('#lines').append($('

    ').append($('').text(from), msg)); + } + + // dom manipulation + $(function () { + $('#set-nickname').submit(function (ev) { + socket.emit('nickname', $('#nick').val(), function (set) { + if (!set) { + clear(); + return $('#chat').addClass('nickname-set'); + } + $('#nickname-err').css('visibility', 'visible'); + }); + return false; + }); + + $('#send-message').submit(function () { + message('me', $('#message').val()); + socket.emit('user message', $('#message').val()); + clear(); + $('#lines').get(0).scrollTop = 10000000; + return false; + }); + + function clear () { + $('#message').val('').focus(); + }; + }); + body + #chat + #nickname + form.wrap#set-nickname + p Please type in your nickname and press enter. + input#nick + p#nickname-err Nickname already in use + #connecting + .wrap Connecting to socket.io server + #messages + #nicknames + #lines + form#send-message + input#message + button Send diff --git a/NodeDrawing/node_modules/socket.io/examples/chat/package.json b/NodeDrawing/node_modules/socket.io/examples/chat/package.json new file mode 100644 index 0000000..f095e85 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/chat/package.json @@ -0,0 +1,11 @@ +{ + "name": "chat.io" + , "description": "example chat application with socket.io" + , "version": "0.0.1" + , "dependencies": { + "express": "2.3.11" + , "jade": "0.12.1" + , "stylus": "0.13.3" + , "nib": "0.0.8" + } +} diff --git a/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl b/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl new file mode 100644 index 0000000..fb5644c --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/mixins.styl @@ -0,0 +1,96 @@ +border-radius(n) + -webkit-border-radius n + -moz-border-radius n + border-radius n + +// replace str with val + +replace(expr, str, val) + expr = clone(expr) + for e, i in expr + if str == e + expr[i] = val + expr + +// normalize gradient point (webkit) + +grad-point(pos) + if length(pos) == 1 + return left pos if pos in (top bottom) + return pos top if pos in (left right) + else if pos[0] in (top bottom) + pos[1] pos[0] + else + pos + +// implicit color stop position + +pos-in-stops(i, stops) + len = length(stops) + if len - 1 == i + 100% + else if i + unit(i / len * 100, '%') + else + 0% + +// normalize color stops +// - (color pos) -> (pos color) +// - (color) -> (implied-pos color) + +normalize-stops(stops) + stops = clone(stops) + for stop, i in stops + if length(stop) == 1 + color = stop[0] + stop[0] = pos-in-stops(i, stops) + stop[1] = color + else if typeof(stop[1]) == 'unit' + pos = stop[1] + stop[1] = stop[0] + stop[0] = pos + stops + +// join color stops with the given translation function + +join-stops(stops, translate) + str = '' + len = length(stops) + for stop, i in stops + str += ', ' if i + pos = stop[0] + color = stop[1] + str += translate(color, pos) + unquote(str) + +// webkit translation function + +webkit-stop(color, pos) + s('color-stop(%d, %s)', pos / 100, color) + +// mozilla translation function + +moz-stop(color, pos) + s('%s %s', color, pos) + +// create a linear gradient with the given start +// position, followed by color stops + +linear-gradient(start, stops...) + error('color stops required') unless length(stops) + prop = current-property[0] + val = current-property[1] + stops = normalize-stops(stops) + + // webkit + end = grad-point(opposite-position(start)) + webkit = s('-webkit-gradient(linear, %s, %s, %s)', grad-point(start), end, join-stops(stops, webkit-stop)) + add-property(prop, replace(val, '__CALL__', webkit)) + + // moz + stops = join-stops(stops, moz-stop) + moz = s('-moz-linear-gradient(%s, %s)', start, stops) + add-property(prop, replace(val, '__CALL__', moz)) + + // literal + s('linear-gradient(%s, %s)', start, stops) diff --git a/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/style.css b/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/style.css new file mode 100644 index 0000000..42cf98f --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/style.css @@ -0,0 +1,188 @@ +#chat, +#nickname, +#messages { + width: 600px; +} +#chat { + position: relative; + border: 1px solid #ccc; +} +#nickname, +#connecting { + position: absolute; + height: 410px; + z-index: 100; + left: 0; + top: 0; + background: #fff; + text-align: center; + width: 600px; + font: 15px Georgia; + color: #666; + display: block; +} +#nickname .wrap, +#connecting .wrap { + padding-top: 150px; +} +#nickname input { + border: 1px solid #ccc; + padding: 10px; +} +#nickname input:focus { + border-color: #999; + outline: 0; +} +#nickname #nickname-err { + color: #8b0000; + font-size: 12px; + visibility: hidden; +} +.connected #connecting { + display: none; +} +.nickname-set #nickname { + display: none; +} +#messages { + height: 380px; + background: #eee; +} +#messages em { + text-shadow: 0 1px 0 #fff; + color: #999; +} +#messages p { + padding: 0; + margin: 0; + font: 12px Helvetica, Arial; + padding: 5px 10px; +} +#messages p b { + display: inline-block; + padding-right: 10px; +} +#messages p:nth-child(even) { + background: #fafafa; +} +#messages #nicknames { + background: #ccc; + padding: 2px 4px 4px; + font: 11px Helvetica; +} +#messages #nicknames span { + color: #000; +} +#messages #nicknames b { + display: inline-block; + color: #fff; + background: #999; + padding: 3px 6px; + margin-right: 5px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + text-shadow: 0 1px 0 #666; +} +#messages #lines { + height: 355px; + overflow: auto; + overflow-x: hidden; + overflow-y: auto; +} +#messages #lines::-webkit-scrollbar { + width: 6px; + height: 6px; +} +#messages #lines::-webkit-scrollbar-button:start:decrement, +#messages #lines ::-webkit-scrollbar-button:end:increment { + display: block; + height: 10px; +} +#messages #lines::-webkit-scrollbar-button:vertical:increment { + background-color: #fff; +} +#messages #lines::-webkit-scrollbar-track-piece { + background-color: #fff; + -webkit-border-radius: 3px; +} +#messages #lines::-webkit-scrollbar-thumb:vertical { + height: 50px; + background-color: #ccc; + -webkit-border-radius: 3px; +} +#messages #lines::-webkit-scrollbar-thumb:horizontal { + width: 50px; + background-color: #fff; + -webkit-border-radius: 3px; +} +#send-message { + background: #fff; + position: relative; +} +#send-message input { + border: none; + height: 30px; + padding: 0 10px; + line-height: 30px; + vertical-align: middle; + width: 580px; +} +#send-message input:focus { + outline: 0; +} +#send-message button { + position: absolute; + top: 5px; + right: 5px; +} +button { + margin: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + display: inline-block; + text-decoration: none; + background: #43a1f7; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #377ad0)); + background: -webkit-linear-gradient(top, #43a1f7 0%, #377ad0 100%); + background: -moz-linear-gradient(top, #43a1f7 0%, #377ad0 100%); + background: linear-gradient(top, #43a1f7 0%, #377ad0 100%); + border: 1px solid #2e70c4; + -webkit-border-radius: 16px; + -moz-border-radius: 16px; + border-radius: 16px; + color: #fff; + font-family: "lucida grande", sans-serif; + font-size: 11px; + font-weight: normal; + line-height: 1; + padding: 3px 10px 5px 10px; + text-align: center; + text-shadow: 0 -1px 1px #2d6dc0; +} +button:hover, +button.hover { + background: darker; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #2e70c4)); + background: -webkit-linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + background: -moz-linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + background: linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + border: 1px solid #2e70c4; + cursor: pointer; + text-shadow: 0 -1px 1px #2c6bbb; +} +button:active, +button.active { + background: #2e70c4; + border: 1px solid #2e70c4; + border-bottom: 1px solid #2861aa; + text-shadow: 0 -1px 1px #2b67b5; +} +button:focus, +button.focus { + outline: none; + -webkit-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; + -moz-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; + box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; +} diff --git a/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/style.styl b/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/style.styl new file mode 100644 index 0000000..6289c94 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/chat/public/stylesheets/style.styl @@ -0,0 +1,118 @@ +@import 'nib' + +#chat, #nickname, #messages + width 600px + +#chat + position relative + border 1px solid #ccc + +#nickname, #connecting + position absolute + height 410px + z-index 100 + left 0 + top 0 + background #fff + text-align center + width 600px + font 15px Georgia + color #666 + display block + .wrap + padding-top 150px + +#nickname + input + border 1px solid #ccc + padding 10px + &:focus + border-color #999 + outline 0 + #nickname-err + color darkred + font-size 12px + visibility hidden + +.connected + #connecting + display none + +.nickname-set + #nickname + display none + +#messages + height 380px + background #eee + em + text-shadow 0 1px 0 #fff + color #999 + p + padding 0 + margin 0 + font 12px Helvetica, Arial + padding 5px 10px + b + display inline-block + padding-right 10px + p:nth-child(even) + background #fafafa + #nicknames + background #ccc + padding 2px 4px 4px + font 11px Helvetica + span + color black + b + display inline-block + color #fff + background #999 + padding 3px 6px + margin-right 5px + border-radius 10px + text-shadow 0 1px 0 #666 + #lines + height 355px + overflow auto + overflow-x hidden + overflow-y auto + &::-webkit-scrollbar + width 6px + height 6px + &::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment + display block + height 10px + &::-webkit-scrollbar-button:vertical:increment + background-color #fff + &::-webkit-scrollbar-track-piece + background-color #fff + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:vertical + height 50px + background-color #ccc + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:horizontal + width 50px + background-color #fff + -webkit-border-radius 3px + +#send-message + background #fff + position relative + input + border none + height 30px + padding 0 10px + line-height 30px + vertical-align middle + width 580px + &:focus + outline 0 + button + position absolute + top 5px + right 5px + +button + download-button() diff --git a/NodeDrawing/node_modules/socket.io/examples/irc-output/app.js b/NodeDrawing/node_modules/socket.io/examples/irc-output/app.js new file mode 100644 index 0000000..591ec2a --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/irc-output/app.js @@ -0,0 +1,81 @@ + +/** + * Bootstrap app. + */ + +require.paths.unshift(__dirname + '/../../lib/'); + +/** + * Module dependencies. + */ + +var express = require('express') + , stylus = require('stylus') + , nib = require('nib') + , sio = require('socket.io') + , irc = require('./irc'); + +/** + * App. + */ + +var app = express.createServer(); + +/** + * App configuration. + */ + +app.configure(function () { + app.use(stylus.middleware({ src: __dirname + '/public', compile: compile })) + app.use(express.static(__dirname + '/public')); + app.set('views', __dirname); + app.set('view engine', 'jade'); + + function compile (str, path) { + return stylus(str) + .set('filename', path) + .use(nib()); + }; +}); + +/** + * App routes. + */ + +app.get('/', function (req, res) { + res.render('index', { layout: false }); +}); + +/** + * App listen. + */ + +app.listen(3000, function () { + var addr = app.address(); + console.log(' app listening on http://' + addr.address + ':' + addr.port); +}); + +/** + * Socket.IO server + */ + +var io = sio.listen(app) + +/** + * Connect to IRC. + */ + +var client = new irc.Client('irc.freenode.net', 6667); +client.connect('socketio\\test\\' + String(Math.random()).substr(-3)); +client.on('001', function () { + this.send('JOIN', '#node.js'); +}); +client.on('PART', function (prefix) { + io.sockets.emit('announcement', irc.user(prefix) + ' left the channel'); +}); +client.on('JOIN', function (prefix) { + io.sockets.emit('announcement', irc.user(prefix) + ' joined the channel'); +}); +client.on('PRIVMSG', function (prefix, channel, text) { + io.sockets.emit('irc message', irc.user(prefix), text); +}); diff --git a/NodeDrawing/node_modules/socket.io/examples/irc-output/index.jade b/NodeDrawing/node_modules/socket.io/examples/irc-output/index.jade new file mode 100644 index 0000000..5468632 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/irc-output/index.jade @@ -0,0 +1,28 @@ +doctype 5 +html + head + link(href='/stylesheets/style.css', rel='stylesheet') + script(src='http://code.jquery.com/jquery-1.6.1.min.js') + script(src='/socket.io/socket.io.js') + script + var socket = io.connect(); + + socket.on('connect', function () { + $('#irc').addClass('connected'); + }); + + socket.on('announcement', function (msg) { + $('#messages').append($('

    ').append($('').text(msg))); + $('#messages').get(0).scrollTop = 10000000; + }); + + socket.on('irc message', function (user, msg) { + $('#messages').append($('

    ').append($('').text(user), msg)); + $('#messages').get(0).scrollTop = 10000000; + }); + body + h2 Node.JS IRC + #irc + #connecting + .wrap Connecting to socket.io server + #messages diff --git a/NodeDrawing/node_modules/socket.io/examples/irc-output/irc.js b/NodeDrawing/node_modules/socket.io/examples/irc-output/irc.js new file mode 100644 index 0000000..c89ddb0 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/irc-output/irc.js @@ -0,0 +1,164 @@ +/** + * From https://github.com/felixge/nodelog/ + */ + +var sys = require('sys'); +var tcp = require('net'); +var irc = exports; + +function bind(fn, scope) { + var bindArgs = Array.prototype.slice.call(arguments); + bindArgs.shift(); + bindArgs.shift(); + + return function() { + var args = Array.prototype.slice.call(arguments); + fn.apply(scope, bindArgs.concat(args)); + }; +} + +function each(set, iterator) { + for (var i = 0; i < set.length; i++) { + var r = iterator(set[i], i); + if (r === false) { + return; + } + } +} + +var Client = irc.Client = function(host, port) { + this.host = host || 'localhost'; + this.port = port || 6667; + + this.connection = null; + this.buffer = ''; + this.encoding = 'utf8'; + this.timeout = 10 * 60 * 60 * 1000; + + this.nick = null; + this.user = null; + this.real = null; +} +sys.inherits(Client, process.EventEmitter); + +Client.prototype.connect = function(nick, user, real) { + var connection = tcp.createConnection(this.port, this.host); + connection.setEncoding(this.encoding); + connection.setTimeout(this.timeout); + connection.addListener('connect', bind(this.onConnect, this)); + connection.addListener('data', bind(this.onReceive, this)); + connection.addListener('end', bind(this.onEof, this)); + connection.addListener('timeout', bind(this.onTimeout, this)); + connection.addListener('close', bind(this.onClose, this)); + + this.nick = nick; + this.user = user || 'guest'; + this.real = real || 'Guest'; + + this.connection = connection; +}; + +Client.prototype.disconnect = function(why) { + if (this.connection.readyState !== 'closed') { + this.connection.close(); + sys.puts('disconnected (reason: '+why+')'); + this.emit('DISCONNECT', why); + } +}; + +Client.prototype.send = function(arg1) { + if (this.connection.readyState !== 'open') { + return this.disconnect('cannot send with readyState: '+this.connection.readyState); + } + + var message = []; + for (var i = 0; i< arguments.length; i++) { + if (arguments[i]) { + message.push(arguments[i]); + } + } + message = message.join(' '); + + sys.puts('> '+message); + message = message + "\r\n"; + this.connection.write(message, this.encoding); +}; + +Client.prototype.parse = function(message) { + var match = message.match(/(?:(:[^\s]+) )?([^\s]+) (.+)/); + var parsed = { + prefix: match[1], + command: match[2] + }; + + var params = match[3].match(/(.*?) ?:(.*)/); + if (params) { + // Params before : + params[1] = (params[1]) + ? params[1].split(' ') + : []; + // Rest after : + params[2] = params[2] + ? [params[2]] + : []; + + params = params[1].concat(params[2]); + } else { + params = match[3].split(' '); + } + + parsed.params = params; + return parsed; +}; + +Client.prototype.onConnect = function() { + this.send('NICK', this.nick); + this.send('USER', this.user, '0', '*', ':'+this.real); +}; + +Client.prototype.onReceive = function(chunk) { + this.buffer = this.buffer + chunk; + + while (this.buffer) { + var offset = this.buffer.indexOf("\r\n"); + if (offset < 0) { + return; + } + + var message = this.buffer.substr(0, offset); + this.buffer = this.buffer.substr(offset + 2); + sys.puts('< '+message); + + message = this.parse(message); + + this.emit.apply(this, [message.command, message.prefix].concat(message.params)); + + if (message !== false) { + this.onMessage(message); + } + } +}; + +Client.prototype.onMessage = function(message) { + switch (message.command) { + case 'PING': + this.send('PONG', ':'+message.params[0]); + break; + } +}; + +Client.prototype.onEof = function() { + this.disconnect('eof'); +}; + +Client.prototype.onTimeout = function() { + this.disconnect('timeout'); +}; + +Client.prototype.onClose = function() { + this.disconnect('close'); +}; + +exports.user = function(prefix) { + return prefix.match(/:([^!]+)!/)[1] +}; diff --git a/NodeDrawing/node_modules/socket.io/examples/irc-output/package.json b/NodeDrawing/node_modules/socket.io/examples/irc-output/package.json new file mode 100644 index 0000000..88bf42f --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/irc-output/package.json @@ -0,0 +1,10 @@ +{ + "name": "socket.io-irc" + , "version": "0.0.1" + , "dependencies": { + "express": "2.3.11" + , "jade": "0.12.1" + , "stylus": "0.13.3" + , "nib": "0.0.8" + } +} diff --git a/NodeDrawing/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl b/NodeDrawing/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl new file mode 100644 index 0000000..2713512 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/examples/irc-output/public/stylesheets/style.styl @@ -0,0 +1,69 @@ +@import 'nib' + +h2 + font bold 18px Helvetica Neue, Arial + +#irc, #messages + width 600px + +#irc + position relative + border 1px solid #ccc + +#connecting + position absolute + height 410px + z-index 100 + left 0 + top 0 + background #fff + text-align center + width 600px + font 15px Georgia + color #666 + display block + .wrap + padding-top 150px + +.connected + #connecting + display none + +#messages + height 380px + background #eee + overflow auto + overflow-x hidden + overflow-y auto + &::-webkit-scrollbar + width 6px + height 6px + &::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment + display block + height 10px + &::-webkit-scrollbar-button:vertical:increment + background-color #fff + &::-webkit-scrollbar-track-piece + background-color #fff + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:vertical + height 50px + background-color #ccc + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:horizontal + width 50px + background-color #fff + -webkit-border-radius 3px + em + text-shadow 0 1px 0 #fff + color #999 + p + padding 0 + margin 0 + font 12px Helvetica, Arial + padding 5px 10px + b + display inline-block + padding-right 10px + p:nth-child(even) + background #fafafa diff --git a/NodeDrawing/node_modules/socket.io/index.js b/NodeDrawing/node_modules/socket.io/index.js new file mode 100644 index 0000000..cc00c10 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/index.js @@ -0,0 +1,8 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +module.exports = require('./lib/socket.io'); diff --git a/NodeDrawing/node_modules/socket.io/lib/logger.js b/NodeDrawing/node_modules/socket.io/lib/logger.js new file mode 100644 index 0000000..ce480ea --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/logger.js @@ -0,0 +1,96 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var util = require('./util') + , toArray = util.toArray; + +/** + * Log levels. + */ + +var levels = [ + 'error' + , 'warn' + , 'info' + , 'debug' +]; + +/** + * Colors for log levels. + */ + +var colors = [ + 31 + , 33 + , 36 + , 90 +]; + +/** + * Pads the nice output to the longest log level. + */ + +function pad (str) { + var max = 0; + + for (var i = 0, l = levels.length; i < l; i++) + max = Math.max(max, levels[i].length); + + if (str.length < max) + return str + new Array(max - str.length + 1).join(' '); + + return str; +}; + +/** + * Logger (console). + * + * @api public + */ + +var Logger = module.exports = function (opts) { + opts = opts || {} + this.colors = false !== opts.colors; + this.level = 3; +}; + +/** + * Log method. + * + * @api public + */ + +Logger.prototype.log = function (type) { + var index = levels.indexOf(type); + + if (index > this.level) + return this; + + console.log.apply( + console + , [this.colors + ? ' \033[' + colors[index] + 'm' + pad(type) + ' -\033[39m' + : type + ':' + ].concat(toArray(arguments).slice(1)) + ); + + return this; +}; + +/** + * Generate methods. + */ + +levels.forEach(function (name) { + Logger.prototype[name] = function () { + this.log.apply(this, [name].concat(toArray(arguments))); + }; +}); diff --git a/NodeDrawing/node_modules/socket.io/lib/manager.js b/NodeDrawing/node_modules/socket.io/lib/manager.js new file mode 100644 index 0000000..d0d02be --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/manager.js @@ -0,0 +1,1020 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , url = require('url') + , util = require('./util') + , store = require('./store') + , client = require('socket.io-client') + , transports = require('./transports') + , Logger = require('./logger') + , Socket = require('./socket') + , MemoryStore = require('./stores/memory') + , SocketNamespace = require('./namespace') + , EventEmitter = process.EventEmitter; + +/** + * Export the constructor. + */ + +exports = module.exports = Manager; + +/** + * Default transports. + */ + +var defaultTransports = exports.defaultTransports = [ + 'websocket' + , 'htmlfile' + , 'xhr-polling' + , 'jsonp-polling' +]; + +/** + * Inherited defaults. + */ + +var parent = module.parent.exports + , protocol = parent.protocol; + +/** + * Manager constructor. + * + * @param {HTTPServer} server + * @param {Object} options, optional + * @api public + */ + +function Manager (server, options) { + this.server = server; + this.namespaces = {}; + this.sockets = this.of(''); + this.settings = { + origins: '*:*' + , log: true + , store: new MemoryStore + , logger: new Logger + , heartbeats: true + , resource: '/socket.io' + , transports: defaultTransports + , authorization: false + , 'log level': 3 + , 'close timeout': 25 + , 'heartbeat timeout': 15 + , 'heartbeat interval': 20 + , 'polling duration': 20 + , 'flash policy server': true + , 'flash policy port': 843 + , 'destroy upgrade': true + , 'browser client': true + , 'browser client minification': false + , 'browser client etag': false + , 'browser client handler': false + , 'client store expiration': 15 + }; + + for (var i in options) { + this.settings[i] = options[i]; + } + + this.initStore(); + + // reset listeners + this.oldListeners = server.listeners('request'); + server.removeAllListeners('request'); + + var self = this; + + server.on('request', function (req, res) { + self.handleRequest(req, res); + }); + + server.on('upgrade', function (req, socket, head) { + self.handleUpgrade(req, socket, head); + }); + + server.on('close', function () { + clearInterval(self.gc); + }); + + // run our private gc every 10 seconds + this.gc = setInterval(this.garbageCollection.bind(this), 10000); + + for (var i in transports) { + if (transports[i].init) { + transports[i].init(this); + } + } + + this.log.info('socket.io started'); +}; + +Manager.prototype.__proto__ = EventEmitter.prototype + +/** + * Store accessor shortcut. + * + * @api public + */ + +Manager.prototype.__defineGetter__('store', function () { + var store = this.get('store'); + store.manager = this; + return store; +}); + +/** + * Logger accessor. + * + * @api public + */ + +Manager.prototype.__defineGetter__('log', function () { + if (this.disabled('log')) return; + + var logger = this.get('logger'); + logger.level = this.get('log level'); + + return logger; +}); + +/** + * Get settings. + * + * @api public + */ + +Manager.prototype.get = function (key) { + return this.settings[key]; +}; + +/** + * Set settings + * + * @api public + */ + +Manager.prototype.set = function (key, value) { + if (arguments.length == 1) return this.get(key); + this.settings[key] = value; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Enable a setting + * + * @api public + */ + +Manager.prototype.enable = function (key) { + this.settings[key] = true; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Disable a setting + * + * @api public + */ + +Manager.prototype.disable = function (key) { + this.settings[key] = false; + this.emit('set:' + key, this.settings[key], key); + return this; +}; + +/** + * Checks if a setting is enabled + * + * @api public + */ + +Manager.prototype.enabled = function (key) { + return !!this.settings[key]; +}; + +/** + * Checks if a setting is disabled + * + * @api public + */ + +Manager.prototype.disabled = function (key) { + return !this.settings[key]; +}; + +/** + * Configure callbacks. + * + * @api public + */ + +Manager.prototype.configure = function (env, fn) { + if ('function' == typeof env) { + env.call(this); + } else if (env == process.env.NODE_ENV) { + fn.call(this); + } + + return this; +}; + +/** + * Initializes everything related to the message dispatcher. + * + * @api private + */ + +Manager.prototype.initStore = function () { + this.handshaken = {}; + this.connected = {}; + this.open = {}; + this.closed = {}; + this.closedA = []; + this.rooms = {}; + this.roomClients = {}; + + var self = this; + + this.store.subscribe('handshake', function (id, data) { + self.onHandshake(id, data); + }); + + this.store.subscribe('connect', function (id) { + self.onConnect(id); + }); + + this.store.subscribe('open', function (id) { + self.onOpen(id); + }); + + this.store.subscribe('join', function (id, room) { + self.onJoin(id, room); + }); + + this.store.subscribe('leave', function (id, room) { + self.onLeave(id, room); + }); + + this.store.subscribe('close', function (id) { + self.onClose(id); + }); + + this.store.subscribe('dispatch', function (room, packet, volatile, exceptions) { + self.onDispatch(room, packet, volatile, exceptions); + }); + + this.store.subscribe('disconnect', function (id) { + self.onDisconnect(id); + }); +}; + +/** + * Called when a client handshakes. + * + * @param text + */ + +Manager.prototype.onHandshake = function (id, data) { + this.handshaken[id] = data; +}; + +/** + * Called when a client connects (ie: transport first opens) + * + * @api private + */ + +Manager.prototype.onConnect = function (id) { + this.connected[id] = true; +}; + +/** + * Called when a client opens a request in a different node. + * + * @api private + */ + +Manager.prototype.onOpen = function (id) { + this.open[id] = true; + + // if we were buffering messages for the client, clear them + if (this.closed[id]) { + var self = this; + + this.closedA.splice(this.closedA.indexOf(id), 1); + + this.store.unsubscribe('dispatch:' + id, function () { + delete self.closed[id]; + }); + } + + // clear the current transport + if (this.transports[id]) { + this.transports[id].discard(); + this.transports[id] = null; + } +}; + +/** + * Called when a message is sent to a namespace and/or room. + * + * @api private + */ + +Manager.prototype.onDispatch = function (room, packet, volatile, exceptions) { + if (this.rooms[room]) { + for (var i = 0, l = this.rooms[room].length; i < l; i++) { + var id = this.rooms[room][i]; + + if (!~exceptions.indexOf(id)) { + if (this.transports[id] && this.transports[id].open) { + this.transports[id].onDispatch(packet, volatile); + } else if (!volatile) { + this.onClientDispatch(id, packet); + } + } + } + } +}; + +/** + * Called when a client joins a nsp / room. + * + * @api private + */ + +Manager.prototype.onJoin = function (id, name) { + if (!this.roomClients[id]) { + this.roomClients[id] = {}; + } + + if (!this.rooms[name]) { + this.rooms[name] = []; + } + + if (!~this.rooms[name].indexOf(id)) { + this.rooms[name].push(id); + this.roomClients[id][name] = true; + } +}; + +/** + * Called when a client leaves a nsp / room. + * + * @param private + */ + +Manager.prototype.onLeave = function (id, room) { + if (this.rooms[room]) { + var index = this.rooms[room].indexOf(id); + + if (index >= 0) { + this.rooms[room].splice(index, 1); + } + + if (!this.rooms[room].length) { + delete this.rooms[room]; + } + delete this.roomClients[id][room]; + } +}; + +/** + * Called when a client closes a request in different node. + * + * @api private + */ + +Manager.prototype.onClose = function (id) { + if (this.open[id]) { + delete this.open[id]; + } + + this.closed[id] = []; + this.closedA.push(id); + + var self = this; + + this.store.subscribe('dispatch:' + id, function (packet, volatile) { + if (!volatile) { + self.onClientDispatch(id, packet); + } + }); +}; + +/** + * Dispatches a message for a closed client. + * + * @api private + */ + +Manager.prototype.onClientDispatch = function (id, packet) { + if (this.closed[id]) { + this.closed[id].push(packet); + } +}; + +/** + * Receives a message for a client. + * + * @api private + */ + +Manager.prototype.onClientMessage = function (id, packet) { + if (this.namespaces[packet.endpoint]) { + this.namespaces[packet.endpoint].handlePacket(id, packet); + } +}; + +/** + * Fired when a client disconnects (not triggered). + * + * @api private + */ + +Manager.prototype.onClientDisconnect = function (id, reason) { + for (var name in this.namespaces) { + if (this.roomClients[id][name]) { + this.namespaces[name].handleDisconnect(id, reason); + } + } + + this.onDisconnect(id); +}; + +/** + * Called when a client disconnects. + * + * @param text + */ + +Manager.prototype.onDisconnect = function (id, local) { + delete this.handshaken[id]; + + if (this.open[id]) { + delete this.open[id]; + } + + if (this.connected[id]) { + delete this.connected[id]; + } + + if (this.transports[id]) { + this.transports[id].discard(); + delete this.transports[id]; + } + + if (this.closed[id]) { + delete this.closed[id]; + this.closedA.splice(this.closedA.indexOf(id), 1); + } + + if (this.roomClients[id]) { + for (var room in this.roomClients[id]) { + this.onLeave(id, room); + } + delete this.roomClients[id] + } + + this.store.destroyClient(id, this.get('client store expiration')); + + this.store.unsubscribe('dispatch:' + id); + + if (local) { + this.store.unsubscribe('message:' + id); + this.store.unsubscribe('disconnect:' + id); + } +}; + +/** + * Handles an HTTP request. + * + * @api private + */ + +Manager.prototype.handleRequest = function (req, res) { + var data = this.checkRequest(req); + + if (!data) { + for (var i = 0, l = this.oldListeners.length; i < l; i++) { + this.oldListeners[i].call(this.server, req, res); + } + + return; + } + + if (data.static || !data.transport && !data.protocol) { + if (data.static && this.enabled('browser client')) { + this.handleClientRequest(req, res, data); + } else { + res.writeHead(200); + res.end('Welcome to socket.io.'); + + this.log.info('unhandled socket.io url'); + } + + return; + } + + if (data.protocol != protocol) { + res.writeHead(500); + res.end('Protocol version not supported.'); + + this.log.info('client protocol version unsupported'); + } else { + if (data.id) { + this.handleHTTPRequest(data, req, res); + } else { + this.handleHandshake(data, req, res); + } + } +}; + +/** + * Handles an HTTP Upgrade. + * + * @api private + */ + +Manager.prototype.handleUpgrade = function (req, socket, head) { + var data = this.checkRequest(req) + , self = this; + + if (!data) { + if (this.enabled('destroy upgrade')) { + socket.end(); + this.log.debug('destroying non-socket.io upgrade'); + } + + return; + } + + req.head = head; + this.handleClient(data, req); +}; + +/** + * Handles a normal handshaken HTTP request (eg: long-polling) + * + * @api private + */ + +Manager.prototype.handleHTTPRequest = function (data, req, res) { + req.res = res; + this.handleClient(data, req); +}; + +/** + * Intantiantes a new client. + * + * @api private + */ + +Manager.prototype.handleClient = function (data, req) { + var socket = req.socket + , store = this.store + , self = this; + + if (undefined != data.query.disconnect) { + if (this.transports[data.id] && this.transports[data.id].open) { + this.transports[data.id].onForcedDisconnect(); + } else { + this.store.publish('disconnect-force:' + data.id); + } + return; + } + + if (!~this.get('transports').indexOf(data.transport)) { + this.log.warn('unknown transport: "' + data.transport + '"'); + req.connection.end(); + return; + } + + var transport = new transports[data.transport](this, data, req) + , handshaken = this.handshaken[data.id]; + + if (handshaken) { + if (transport.open) { + if (this.closed[data.id] && this.closed[data.id].length) { + transport.payload(this.closed[data.id]); + this.closed[data.id] = []; + } + + this.onOpen(data.id); + this.store.publish('open', data.id); + this.transports[data.id] = transport; + } + + if (!this.connected[data.id]) { + this.onConnect(data.id); + this.store.publish('connect', data.id); + + // flag as used + delete handshaken.issued; + this.onHandshake(data.id, handshaken); + this.store.publish('handshake', data.id, handshaken); + + // initialize the socket for all namespaces + for (var i in this.namespaces) { + var socket = this.namespaces[i].socket(data.id, true); + + // echo back connect packet and fire connection event + if (i === '') { + this.namespaces[i].handlePacket(data.id, { type: 'connect' }); + } + } + + this.store.subscribe('message:' + data.id, function (packet) { + self.onClientMessage(data.id, packet); + }); + + this.store.subscribe('disconnect:' + data.id, function (reason) { + self.onClientDisconnect(data.id, reason); + }); + } + } else { + if (transport.open) { + transport.error('client not handshaken', 'reconnect'); + } + + transport.discard(); + } +}; + +/** + * Dictionary for static file serving + * + * @api public + */ + +Manager.static = { + cache: {} + , paths: { + '/static/flashsocket/WebSocketMain.swf': client.dist + '/WebSocketMain.swf' + , '/static/flashsocket/WebSocketMainInsecure.swf': + client.dist + '/WebSocketMainInsecure.swf' + , '/socket.io.js': client.dist + '/socket.io.js' + , '/socket.io.js.min': client.dist + '/socket.io.min.js' + } + , mime: { + 'js': { + contentType: 'application/javascript' + , encoding: 'utf8' + } + , 'swf': { + contentType: 'application/x-shockwave-flash' + , encoding: 'binary' + } + } +}; + +/** + * Serves the client. + * + * @api private + */ + +Manager.prototype.handleClientRequest = function (req, res, data) { + var static = Manager.static + , extension = data.path.split('.').pop() + , file = data.path + (this.enabled('browser client minification') + && extension == 'js' ? '.min' : '') + , location = static.paths[file] + , cache = static.cache[file]; + + var self = this; + + /** + * Writes a response, safely + * + * @api private + */ + + function write (status, headers, content, encoding) { + try { + res.writeHead(status, headers || null); + res.end(content || '', encoding || null); + } catch (e) {} + } + + function serve () { + if (req.headers['if-none-match'] === cache.Etag) { + return write(304); + } + + var mime = static.mime[extension] + , headers = { + 'Content-Type': mime.contentType + , 'Content-Length': cache.length + }; + + if (self.enabled('browser client etag') && cache.Etag) { + headers.Etag = cache.Etag; + } + + write(200, headers, cache.content, mime.encoding); + self.log.debug('served static ' + data.path); + } + + if (this.get('browser client handler')) { + this.get('browser client handler').call(this, req, res); + } else if (!cache) { + fs.readFile(location, function (err, data) { + if (err) { + write(500, null, 'Error serving static ' + data.path); + self.log.warn('Can\'t cache '+ data.path +', ' + err.message); + return; + } + + cache = Manager.static.cache[file] = { + content: data + , length: data.length + , Etag: client.version + }; + + serve(); + }); + } else { + serve(); + } +}; + +/** + * Generates a session id. + * + * @api private + */ + +Manager.prototype.generateId = function () { + return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString() + + Math.abs(Math.random() * Math.random() * Date.now() | 0).toString(); +}; + +/** + * Handles a handshake request. + * + * @api private + */ + +Manager.prototype.handleHandshake = function (data, req, res) { + var self = this; + + function writeErr (status, message) { + if (data.query.jsonp) { + res.writeHead(200, { 'Content-Type': 'application/javascript' }); + res.end('io.j[' + data.query.jsonp + '](new Error("' + message + '"));'); + } else { + res.writeHead(status); + res.end(message); + } + }; + + function error (err) { + writeErr(500, 'handshake error'); + self.log.warn('handshake error ' + err); + }; + + if (!this.verifyOrigin(req)) { + writeErr(403, 'handshake bad origin'); + return; + } + + var handshakeData = this.handshakeData(data); + + this.authorize(handshakeData, function (err, authorized, newData) { + if (err) return error(err); + + if (authorized) { + var id = self.generateId() + , hs = [ + id + , self.enabled('heartbeats') ? self.get('heartbeat timeout') || '' : '' + , self.get('close timeout') || '' + , self.transports(data).join(',') + ].join(':'); + + if (data.query.jsonp) { + hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');'; + res.writeHead(200, { 'Content-Type': 'application/javascript' }); + } else { + res.writeHead(200); + } + + res.end(hs); + + self.onHandshake(id, newData || handshakeData); + self.store.publish('handshake', id, newData || handshakeData); + + self.log.info('handshake authorized', id); + } else { + writeErr(403, 'handshake unauthorized'); + self.log.info('handshake unauthorized'); + } + }) +}; + +/** + * Gets normalized handshake data + * + * @api private + */ + +Manager.prototype.handshakeData = function (data) { + var connection = data.request.connection + , connectionAddress + , date = new Date; + + if (connection.remoteAddress) { + connectionAddress = { + address: connection.remoteAddress + , port: connection.remotePort + }; + } else if (connection.socket && connection.socket.remoteAddress) { + connectionAddress = { + address: connection.socket.remoteAddress + , port: connection.socket.remotePort + }; + } + + return { + headers: data.headers + , address: connectionAddress + , time: date.toString() + , query: data.query + , url: data.request.url + , xdomain: !!data.request.headers.origin + , secure: data.request.connection.secure + , issued: +date + }; +}; + +/** + * Verifies the origin of a request. + * + * @api private + */ + +Manager.prototype.verifyOrigin = function (request) { + var origin = request.headers.origin + , origins = this.get('origins'); + + if (origin === 'null') origin = '*'; + + if (origins.indexOf('*:*') !== -1) { + return true; + } + + if (origin) { + try { + var parts = url.parse(origin); + + return + ~origins.indexOf(parts.host + ':' + parts.port) || + ~origins.indexOf(parts.host + ':*') || + ~origins.indexOf('*:' + parts.port); + } catch (ex) {} + } + + return false; +}; + +/** + * Handles an incoming packet. + * + * @api private + */ + +Manager.prototype.handlePacket = function (sessid, packet) { + this.of(packet.endpoint || '').handlePacket(sessid, packet); +}; + +/** + * Performs authentication. + * + * @param Object client request data + * @api private + */ + +Manager.prototype.authorize = function (data, fn) { + if (this.get('authorization')) { + var self = this; + + this.get('authorization').call(this, data, function (err, authorized) { + self.log.debug('client ' + authorized ? 'authorized' : 'unauthorized'); + fn(err, authorized); + }); + } else { + this.log.debug('client authorized'); + fn(null, true); + } + + return this; +}; + +/** + * Retrieves the transports adviced to the user. + * + * @api private + */ + +Manager.prototype.transports = function (data) { + var transp = this.get('transports') + , ret = []; + + for (var i = 0, l = transp.length; i < l; i++) { + var transport = transp[i]; + + if (transport) { + if (!transport.checkClient || transport.checkClient(data)) { + ret.push(transport); + } + } + } + + return ret; +}; + +/** + * Checks whether a request is a socket.io one. + * + * @return {Object} a client request data object or `false` + * @api private + */ + +var regexp = /^\/([^\/]+)\/?([^\/]+)?\/?([^\/]+)?\/?$/ + +Manager.prototype.checkRequest = function (req) { + var resource = this.get('resource'); + + if (req.url.substr(0, resource.length) == resource) { + var uri = url.parse(req.url.substr(resource.length), true) + , path = uri.pathname || '' + , pieces = path.match(regexp); + + // client request data + var data = { + query: uri.query || {} + , headers: req.headers + , request: req + , path: path + }; + + if (pieces) { + data.protocol = Number(pieces[1]); + data.transport = pieces[2]; + data.id = pieces[3]; + data.static = !!Manager.static.paths[path]; + }; + + return data; + } + + return false; +}; + +/** + * Declares a socket namespace + * + * @api public + */ + +Manager.prototype.of = function (nsp) { + if (this.namespaces[nsp]) { + return this.namespaces[nsp]; + } + + return this.namespaces[nsp] = new SocketNamespace(this, nsp); +}; + +/** + * Perform garbage collection on long living objects and properties that cannot + * be removed automatically. + * + * @api private + */ + +Manager.prototype.garbageCollection = function () { + // clean up unused handshakes + var ids = Object.keys(this.handshaken) + , i = ids.length + , now = Date.now() + , handshake; + + while (i--) { + handshake = this.handshaken[ids[i]]; + + if ('issued' in handshake && (now - handshake.issued) >= 3E4) { + this.onDisconnect(ids[i]); + } + } +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/namespace.js b/NodeDrawing/node_modules/socket.io/lib/namespace.js new file mode 100644 index 0000000..d09e5f6 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/namespace.js @@ -0,0 +1,349 @@ +/** + * Module dependencies. + */ + +var Socket = require('./socket') + , EventEmitter = process.EventEmitter + , parser = require('./parser') + , util = require('./util'); + +/** + * Exports the constructor. + */ + +exports = module.exports = SocketNamespace; + +/** + * Constructor. + * + * @api public. + */ + +function SocketNamespace (mgr, name) { + this.manager = mgr; + this.name = name || ''; + this.sockets = {}; + this.auth = false; + this.setFlags(); +}; + +/** + * Inherits from EventEmitter. + */ + +SocketNamespace.prototype.__proto__ = EventEmitter.prototype; + +/** + * Copies emit since we override it + * + * @api private + */ + +SocketNamespace.prototype.$emit = EventEmitter.prototype.emit; + +/** + * Retrieves all clients as Socket instances as an array. + * + * @api public + */ + +SocketNamespace.prototype.clients = function (room) { + var room = this.name + (room !== undefined ? + '/' + room : ''); + + if (!this.manager.rooms[room]) { + return []; + } + + return this.manager.rooms[room].map(function (id) { + return this.socket(id); + }, this); +}; + +/** + * Access logger interface. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * Access store. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('store', function () { + return this.manager.store; +}); + +/** + * JSON message flag. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('json', function () { + this.flags.json = true; + return this; +}); + +/** + * Volatile message flag. + * + * @api public + */ + +SocketNamespace.prototype.__defineGetter__('volatile', function () { + this.flags.volatile = true; + return this; +}); + +/** + * Overrides the room to relay messages to (flag) + * + * @api public + */ + +SocketNamespace.prototype.in = SocketNamespace.prototype.to = function (room) { + this.flags.endpoint = this.name + (room ? '/' + room : ''); + return this; +}; + +/** + * Adds a session id we should prevent relaying messages to (flag) + * + * @api public + */ + +SocketNamespace.prototype.except = function (id) { + this.flags.exceptions.push(id); + return this; +}; + +/** + * Sets the default flags. + * + * @api private + */ + +SocketNamespace.prototype.setFlags = function () { + this.flags = { + endpoint: this.name + , exceptions: [] + }; + return this; +}; + +/** + * Sends out a packet + * + * @api private + */ + +SocketNamespace.prototype.packet = function (packet) { + packet.endpoint = this.name; + + var store = this.store + , log = this.log + , volatile = this.flags.volatile + , exceptions = this.flags.exceptions + , packet = parser.encodePacket(packet); + + this.manager.onDispatch(this.flags.endpoint, packet, volatile, exceptions); + this.store.publish('dispatch', this.flags.endpoint, packet, volatile, exceptions); + + this.setFlags(); + + return this; +}; + +/** + * Sends to everyone. + * + * @api public + */ + +SocketNamespace.prototype.send = function (data) { + return this.packet({ + type: this.flags.json ? 'json' : 'message' + , data: data + }); +}; + +/** + * Emits to everyone (override) + * + * @api private + */ + +SocketNamespace.prototype.emit = function (name) { + if (name == 'newListener') { + return this.$emit.apply(this, arguments); + } + + return this.packet({ + type: 'event' + , name: name + , args: util.toArray(arguments).slice(1) + }); +}; + +/** + * Retrieves or creates a write-only socket for a client, unless specified. + * + * @param {Boolean} whether the socket will be readable when initialized + * @api private + */ + +SocketNamespace.prototype.socket = function (sid, readable) { + if (!this.sockets[sid]) { + this.sockets[sid] = new Socket(this.manager, sid, this, readable); + } + + return this.sockets[sid]; +}; + +/** + * Sets authorization for this namespace + * + * @api public + */ + +SocketNamespace.prototype.authorization = function (fn) { + this.auth = fn; + return this; +}; + +/** + * Called when a socket disconnects entirely. + * + * @api private + */ + +SocketNamespace.prototype.handleDisconnect = function (sid, reason) { + if (this.sockets[sid] && this.sockets[sid].readable) { + this.sockets[sid].onDisconnect(reason); + delete this.sockets[sid]; + } +}; + +/** + * Performs authentication. + * + * @param Object client request data + * @api private + */ + +SocketNamespace.prototype.authorize = function (data, fn) { + if (this.auth) { + var self = this; + + this.auth.call(this, data, function (err, authorized) { + self.log.debug('client ' + + (authorized ? '' : 'un') + 'authorized for ' + self.name); + fn(err, authorized); + }); + } else { + this.log.debug('client authorized for ' + this.name); + fn(null, true); + } + + return this; +}; + +/** + * Handles a packet. + * + * @api private + */ + +SocketNamespace.prototype.handlePacket = function (sessid, packet) { + var socket = this.socket(sessid) + , dataAck = packet.ack == 'data' + , self = this; + + function ack () { + self.log.debug('sending data ack packet'); + socket.packet({ + type: 'ack' + , args: util.toArray(arguments) + , ackId: packet.id + }); + }; + + function error (err) { + self.log.warn('handshake error ' + err + ' for ' + self.name); + socket.packet({ type: 'error', reason: err }); + }; + + function connect () { + self.manager.onJoin(sessid, self.name); + self.store.publish('join', sessid, self.name); + + // packet echo + socket.packet({ type: 'connect' }); + + // emit connection event + self.$emit('connection', socket); + }; + + switch (packet.type) { + case 'connect': + if (packet.endpoint == '') { + connect(); + } else { + var manager = this.manager + , handshakeData = manager.handshaken[sessid]; + + this.authorize(handshakeData, function (err, authorized, newData) { + if (err) return error(err); + + if (authorized) { + manager.onHandshake(sessid, newData || handshakeData); + self.store.publish('handshake', sessid, newData || handshakeData); + connect(); + } else { + error('unauthorized'); + } + }); + } + break; + + case 'ack': + if (socket.acks[packet.ackId]) { + socket.acks[packet.ackId].apply(socket, packet.args); + } else { + this.log.info('unknown ack packet'); + } + break; + + case 'event': + var params = [packet.name].concat(packet.args); + + if (dataAck) + params.push(ack); + + socket.$emit.apply(socket, params); + break; + + case 'disconnect': + this.manager.onLeave(sessid, this.name); + this.store.publish('leave', sessid, this.name); + + socket.$emit('disconnect', packet.reason || 'packet'); + break; + + case 'json': + case 'message': + var params = ['message', packet.data]; + + if (dataAck) + params.push(ack); + + socket.$emit.apply(socket, params); + }; +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/parser.js b/NodeDrawing/node_modules/socket.io/lib/parser.js new file mode 100644 index 0000000..bdb27b2 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/parser.js @@ -0,0 +1,243 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +/** + * Packet types. + */ + +var packets = exports.packets = [ + 'disconnect' + , 'connect' + , 'heartbeat' + , 'message' + , 'json' + , 'event' + , 'ack' + , 'error' + , 'noop' +]; + +/** + * Errors reasons. + */ + +var reasons = exports.reasons = [ + 'transport not supported' + , 'client not handshaken' + , 'unauthorized' +]; + +/** + * Errors advice. + */ + +var advice = exports.advice = [ + 'reconnect' +]; + +/** + * Encodes a packet. + * + * @api private + */ + +exports.encodePacket = function (packet) { + var type = packets.indexOf(packet.type) + , id = packet.id || '' + , endpoint = packet.endpoint || '' + , ack = packet.ack + , data = null; + + switch (packet.type) { + case 'error': + var reason = packet.reason ? reasons.indexOf(packet.reason) : '' + , adv = packet.advice ? advice.indexOf(packet.advice) : '' + + if (reason !== '' || adv !== '') + data = reason + (adv !== '' ? ('+' + adv) : '') + + break; + + case 'message': + if (packet.data !== '') + data = packet.data; + break; + + case 'event': + var ev = { name: packet.name }; + + if (packet.args && packet.args.length) { + ev.args = packet.args; + } + + data = JSON.stringify(ev); + break; + + case 'json': + data = JSON.stringify(packet.data); + break; + + case 'connect': + if (packet.qs) + data = packet.qs; + break; + + case 'ack': + data = packet.ackId + + (packet.args && packet.args.length + ? '+' + JSON.stringify(packet.args) : ''); + break; + } + + // construct packet with required fragments + var encoded = [ + type + , id + (ack == 'data' ? '+' : '') + , endpoint + ]; + + // data fragment is optional + if (data !== null && data !== undefined) + encoded.push(data); + + return encoded.join(':'); +}; + +/** + * Encodes multiple messages (payload). + * + * @param {Array} messages + * @api private + */ + +exports.encodePayload = function (packets) { + var decoded = ''; + + if (packets.length == 1) + return packets[0]; + + for (var i = 0, l = packets.length; i < l; i++) { + var packet = packets[i]; + decoded += '\ufffd' + packet.length + '\ufffd' + packets[i] + } + + return decoded; +}; + +/** + * Decodes a packet + * + * @api private + */ + +var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/; + +exports.decodePacket = function (data) { + var pieces = data.match(regexp); + + if (!pieces) return {}; + + var id = pieces[2] || '' + , data = pieces[5] || '' + , packet = { + type: packets[pieces[1]] + , endpoint: pieces[4] || '' + }; + + // whether we need to acknowledge the packet + if (id) { + packet.id = id; + if (pieces[3]) + packet.ack = 'data'; + else + packet.ack = true; + } + + // handle different packet types + switch (packet.type) { + case 'error': + var pieces = data.split('+'); + packet.reason = reasons[pieces[0]] || ''; + packet.advice = advice[pieces[1]] || ''; + break; + + case 'message': + packet.data = data || ''; + break; + + case 'event': + try { + var opts = JSON.parse(data); + packet.name = opts.name; + packet.args = opts.args; + } catch (e) { } + + packet.args = packet.args || []; + break; + + case 'json': + try { + packet.data = JSON.parse(data); + } catch (e) { } + break; + + case 'connect': + packet.qs = data || ''; + break; + + case 'ack': + var pieces = data.match(/^([0-9]+)(\+)?(.*)/); + if (pieces) { + packet.ackId = pieces[1]; + packet.args = []; + + if (pieces[3]) { + try { + packet.args = pieces[3] ? JSON.parse(pieces[3]) : []; + } catch (e) { } + } + } + break; + + case 'disconnect': + case 'heartbeat': + break; + }; + + return packet; +}; + +/** + * Decodes data payload. Detects multiple messages + * + * @return {Array} messages + * @api public + */ + +exports.decodePayload = function (data) { + if (data[0] == '\ufffd') { + var ret = []; + + for (var i = 1, length = ''; i < data.length; i++) { + if (data[i] == '\ufffd') { + ret.push(exports.decodePacket(data.substr(i + 1).substr(0, length))); + i += Number(length) + 1; + length = ''; + } else { + length += data[i]; + } + } + + return ret; + } else { + return [exports.decodePacket(data)]; + } +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/socket.io.js b/NodeDrawing/node_modules/socket.io/lib/socket.io.js new file mode 100644 index 0000000..ccbd03e --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/socket.io.js @@ -0,0 +1,128 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var client = require('socket.io-client'); + +/** + * Version. + */ + +exports.version = '0.7.8'; + +/** + * Supported protocol version. + */ + +exports.protocol = 1; + +/** + * Client that we serve. + */ + +exports.clientVersion = client.version; + +/** + * Attaches a manager + * + * @param {HTTPServer/Number} a HTTP/S server or a port number to listen on. + * @param {Object} opts to be passed to Manager and/or http server + * @param {Function} callback if a port is supplied + * @api public + */ + +exports.listen = function (server, options, fn) { + if ('function' == typeof options) { + fn = options; + options = {}; + } + + if ('undefined' == typeof server) { + // create a server that listens on port 80 + server = 80; + } + + if ('number' == typeof server) { + // if a port number is passed + var port = server; + + if (options && options.key) + server = require('https').createServer(options); + else + server = require('http').createServer(); + + // default response + server.on('request', function (req, res) { + res.writeHead(200); + res.end('Welcome to socket.io.'); + }); + + server.listen(port, fn); + } + + // otherwise assume a http/s server + return new exports.Manager(server, options); +}; + +/** + * Manager constructor. + * + * @api public + */ + +exports.Manager = require('./manager'); + +/** + * Transport constructor. + * + * @api public + */ + +exports.Transport = require('./transport'); + +/** + * Socket constructor. + * + * @api public + */ + +exports.Socket = require('./socket'); + +/** + * Store constructor. + * + * @api public + */ + +exports.Store = require('./store'); + +/** + * Memory Store constructor. + * + * @api public + */ + +exports.MemoryStore = require('./stores/memory'); + +/** + * Redis Store constructor. + * + * @api public + */ + +exports.RedisStore = require('./stores/redis'); + +/** + * Parser. + * + * @api public + */ + +exports.parser = require('./parser'); diff --git a/NodeDrawing/node_modules/socket.io/lib/socket.js b/NodeDrawing/node_modules/socket.io/lib/socket.js new file mode 100644 index 0000000..22a8abf --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/socket.js @@ -0,0 +1,345 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var parser = require('./parser') + , util = require('./util') + , EventEmitter = process.EventEmitter; + +/** + * Export the constructor. + */ + +exports = module.exports = Socket; + +/** + * Socket constructor. + * + * @param {Manager} manager instance + * @param {String} session id + * @param {Namespace} namespace the socket belongs to + * @param {Boolean} whether the + * @api public + */ + +function Socket (manager, id, nsp, readable) { + this.id = id; + this.namespace = nsp; + this.manager = manager; + this.disconnected = false; + this.ackPackets = 0; + this.acks = {}; + this.setFlags(); + this.readable = readable; + this.store = this.manager.store.client(this.id); +}; + +/** + * Inherits from EventEmitter. + */ + +Socket.prototype.__proto__ = EventEmitter.prototype; + +/** + * Accessor shortcut for the handshake data + * + * @api private + */ + +Socket.prototype.__defineGetter__('handshake', function () { + return this.manager.handshaken[this.id]; +}); + +/** + * Accessor shortcut for the logger. + * + * @api private + */ + +Socket.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * JSON message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('json', function () { + this.flags.json = true; + return this; +}); + +/** + * Volatile message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('volatile', function () { + this.flags.volatile = true; + return this; +}); + +/** + * Broadcast message flag. + * + * @api public + */ + +Socket.prototype.__defineGetter__('broadcast', function () { + this.flags.broadcast = true; + return this; +}); + +/** + * Overrides the room to broadcast messages to (flag) + * + * @api public + */ + +Socket.prototype.to = Socket.prototype.in = function (room) { + this.flags.room = room; + return this; +}; + +/** + * Resets flags + * + * @api private + */ + +Socket.prototype.setFlags = function () { + this.flags = { + endpoint: this.namespace.name + , room: '' + }; + return this; +}; + +/** + * Triggered on disconnect + * + * @api private + */ + +Socket.prototype.onDisconnect = function (reason) { + if (!this.disconnected) { + this.$emit('disconnect', reason); + this.disconnected = true; + } +}; + +/** + * Joins a user to a room. + * + * @api public + */ + +Socket.prototype.join = function (name, fn) { + var nsp = this.namespace.name + , name = (nsp + '/') + name; + + this.manager.onJoin(this.id, name); + this.manager.store.publish('join', this.id, name); + + if (fn) { + this.log.warn('Client#join callback is deprecated'); + fn(); + } + + return this; +}; + +/** + * Joins a user to a room. + * + * @api public + */ + +Socket.prototype.leave = function (name, fn) { + var nsp = this.namespace.name + , name = (nsp + '/') + name; + + this.manager.onLeave(this.id, name); + this.manager.store.publish('leave', this.id, name); + + if (fn) { + this.log.warn('Client#leave callback is deprecated'); + fn(); + } + + return this; +}; + +/** + * Transmits a packet. + * + * @api private + */ + +Socket.prototype.packet = function (packet) { + if (this.flags.broadcast) { + this.log.debug('broadcasting packet'); + this.namespace.in(this.flags.room).except(this.id).packet(packet); + } else { + packet.endpoint = this.flags.endpoint; + packet = parser.encodePacket(packet); + + this.dispatch(packet, this.flags.volatile); + } + + this.setFlags(); + + return this; +}; + +/** + * Dispatches a packet + * + * @api private + */ + +Socket.prototype.dispatch = function (packet, volatile) { + if (this.manager.transports[this.id] && this.manager.transports[this.id].open) { + this.manager.transports[this.id].onDispatch(packet, volatile); + } else { + if (!volatile) { + this.manager.onClientDispatch(this.id, packet, volatile); + } + + this.manager.store.publish('dispatch:' + this.id, packet, volatile); + } +}; + +/** + * Stores data for the client. + * + * @api public + */ + +Socket.prototype.set = function (key, value, fn) { + this.store.set(key, value, fn); + return this; +}; + +/** + * Retrieves data for the client + * + * @api public + */ + +Socket.prototype.get = function (key, fn) { + this.store.get(key, fn); + return this; +}; + +/** + * Checks data for the client + * + * @api public + */ + +Socket.prototype.has = function (key, fn) { + this.store.has(key, fn); + return this; +}; + +/** + * Deletes data for the client + * + * @api public + */ + +Socket.prototype.del = function (key, fn) { + this.store.del(key, fn); + return this; +}; + +/** + * Kicks client + * + * @api public + */ + +Socket.prototype.disconnect = function () { + if (!this.disconnected) { + this.log.info('booting client'); + + if (this.manager.transports[this.id] && this.manager.transports[this.id].open) { + this.manager.transports[this.id].onForcedDisconnect(); + } else { + this.manager.onClientDisconnect(this.id); + this.manager.store.publish('disconnect:' + this.id); + } + } + + return this; +}; + +/** + * Send a message. + * + * @api public + */ + +Socket.prototype.send = function (data, fn) { + var packet = { + type: this.flags.json ? 'json' : 'message' + , data: data + }; + + if (fn) { + packet.id = ++this.ackPackets; + packet.ack = true; + this.acks[packet.id] = fn; + } + + return this.packet(packet); +}; + +/** + * Original emit function. + * + * @api private + */ + +Socket.prototype.$emit = EventEmitter.prototype.emit; + +/** + * Emit override for custom events. + * + * @api public + */ + +Socket.prototype.emit = function (ev) { + if (ev == 'newListener') { + return this.$emit.apply(this, arguments); + } + + var args = util.toArray(arguments).slice(1) + , lastArg = args[args.length - 1] + , packet = { + type: 'event' + , name: ev + }; + + if ('function' == typeof lastArg) { + packet.id = ++this.ackPackets; + packet.ack = lastArg.length ? 'data' : true; + this.acks[packet.id] = lastArg; + args = args.slice(0, args.length - 1); + } + + packet.args = args; + + return this.packet(packet); +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/store.js b/NodeDrawing/node_modules/socket.io/lib/store.js new file mode 100644 index 0000000..06c0389 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/store.js @@ -0,0 +1,98 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Expose the constructor. + */ + +exports = module.exports = Store; + +/** + * Module dependencies. + */ + +var EventEmitter = process.EventEmitter; + +/** + * Store interface + * + * @api public + */ + +function Store (options) { + this.options = options; + this.clients = {}; +}; + +/** + * Inherit from EventEmitter. + */ + +Store.prototype.__proto__ = EventEmitter.prototype; + +/** + * Initializes a client store + * + * @param {String} id + * @api public + */ + +Store.prototype.client = function (id) { + if (!this.clients[id]) { + this.clients[id] = new (this.constructor.Client)(this, id); + } + + return this.clients[id]; +}; + +/** + * Destroys a client + * + * @api {String} sid + * @param {Number} number of seconds to expire client data + * @api private + */ + +Store.prototype.destroyClient = function (id, expiration) { + if (this.clients[id]) { + this.clients[id].destroy(expiration); + delete this.clients[id]; + } + + return this; +}; + +/** + * Destroys the store + * + * @param {Number} number of seconds to expire client data + * @api private + */ + +Store.prototype.destroy = function (clientExpiration) { + var keys = Object.keys(this.clients) + , count = keys.length; + + for (var i = 0, l = count; i < l; i++) { + this.destroyClient(keys[i], clientExpiration); + } + + this.clients = {}; + + return this; +}; + +/** + * Client. + * + * @api public + */ + +Store.Client = function (store, id) { + this.store = store; + this.id = id; +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/stores/memory.js b/NodeDrawing/node_modules/socket.io/lib/stores/memory.js new file mode 100644 index 0000000..8b731a7 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/stores/memory.js @@ -0,0 +1,143 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , Store = require('../store'); + +/** + * Exports the constructor. + */ + +exports = module.exports = Memory; +Memory.Client = Client; + +/** + * Memory store + * + * @api public + */ + +function Memory (opts) { + Store.call(this, opts); +}; + +/** + * Inherits from Store. + */ + +Memory.prototype.__proto__ = Store.prototype; + +/** + * Publishes a message. + * + * @api private + */ + +Memory.prototype.publish = function () { }; + +/** + * Subscribes to a channel + * + * @api private + */ + +Memory.prototype.subscribe = function () { }; + +/** + * Unsubscribes + * + * @api private + */ + +Memory.prototype.unsubscribe = function () { }; + +/** + * Client constructor + * + * @api private + */ + +function Client () { + Store.Client.apply(this, arguments); + this.data = {}; +}; + +/** + * Inherits from Store.Client + */ + +Client.prototype.__proto__ = Store.Client; + +/** + * Gets a key + * + * @api public + */ + +Client.prototype.get = function (key, fn) { + fn(null, this.data[key] === undefined ? null : this.data[key]); + return this; +}; + +/** + * Sets a key + * + * @api public + */ + +Client.prototype.set = function (key, value, fn) { + this.data[key] = value; + fn && fn(null); + return this; +}; + +/** + * Has a key + * + * @api public + */ + +Client.prototype.has = function (key, fn) { + fn(null, key in this.data); +}; + +/** + * Deletes a key + * + * @api public + */ + +Client.prototype.del = function (key, fn) { + delete this.data[key]; + fn && fn(null); + return this; +}; + +/** + * Destroys the client. + * + * @param {Number} number of seconds to expire data + * @api private + */ + +Client.prototype.destroy = function (expiration) { + if ('number' != typeof expiration) { + this.data = {}; + } else { + var self = this; + + setTimeout(function () { + self.data = {}; + }, expiration * 1000); + } + + return this; +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/stores/redis.js b/NodeDrawing/node_modules/socket.io/lib/stores/redis.js new file mode 100644 index 0000000..26f7a92 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/stores/redis.js @@ -0,0 +1,250 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , Store = require('../store') + , assert = require('assert'); + +/** + * Exports the constructor. + */ + +exports = module.exports = Redis; +Redis.Client = Client; + +/** + * Redis store. + * Options: + * - nodeId (fn) gets an id that uniquely identifies this node + * - redis (fn) redis constructor, defaults to redis + * - redisPub (object) options to pass to the pub redis client + * - redisSub (object) options to pass to the sub redis client + * - redisClient (object) options to pass to the general redis client + * - pack (fn) custom packing, defaults to JSON or msgpack if installed + * - unpack (fn) custom packing, defaults to JSON or msgpack if installed + * + * @api public + */ + +function Redis (opts) { + opts = opts || {}; + + // node id to uniquely identify this node + var nodeId = opts.nodeId || function () { + // by default, we generate a random id + return Math.abs(Math.random() * Math.random() * Date.now() | 0); + }; + + this.nodeId = nodeId(); + + // packing / unpacking mechanism + if (opts.pack) { + this.pack = opts.pack; + this.unpack = opts.unpack; + } else { + try { + var msgpack = require('msgpack'); + this.pack = msgpack.pack; + this.unpack = msgpack.unpack; + } catch (e) { + this.pack = JSON.stringify; + this.unpack = JSON.parse; + } + } + + var redis = opts.redis || require('redis'); + + // initialize a pubsub client and a regular client + this.pub = redis.createClient(opts.redisPub); + this.sub = redis.createClient(opts.redisSub); + this.cmd = redis.createClient(opts.redisClient); + + Store.call(this, opts); +}; + +/** + * Inherits from Store. + */ + +Redis.prototype.__proto__ = Store.prototype; + +/** + * Publishes a message. + * + * @api private + */ + +Redis.prototype.publish = function (name) { + var args = Array.prototype.slice.call(arguments, 1); + this.pub.publish(name, this.pack({ nodeId: this.nodeId, args: args })); + this.emit.apply(this, ['publish', name].concat(args)); +}; + +/** + * Subscribes to a channel + * + * @api private + */ + +Redis.prototype.subscribe = function (name, consumer, fn) { + this.sub.subscribe(name); + + if (consumer || fn) { + var self = this; + + self.sub.on('subscribe', function subscribe (ch) { + if (name == ch) { + function message (ch, msg) { + if (name == ch) { + msg = self.unpack(msg); + + // we check that the message consumed wasnt emitted by this node + if (self.nodeId != msg.nodeId) { + consumer.apply(null, msg.args); + } + } + }; + + self.sub.on('message', message); + + self.on('unsubscribe', function unsubscribe (ch) { + if (name == ch) { + self.sub.removeListener('message', message); + self.removeEvent('unsubscribe', unsubscribe); + } + }); + + self.sub.removeListener('subscribe', subscribe); + + fn && fn(); + } + }); + } + + this.emit('subscribe', name, consumer, fn); +}; + +/** + * Unsubscribes + * + * @api private + */ + +Redis.prototype.unsubscribe = function (name, fn) { + this.sub.unsubscribe(name); + + if (fn) { + var client = this.sub; + + client.on('unsubscribe', function unsubscribe (ch) { + if (name == ch) { + fn(); + client.removeListener('unsubscribe', unsubscribe); + } + }); + } + + this.emit('unsubscribe', name, fn); +}; + +/** + * Destroys the store + * + * @api public + */ + +Redis.prototype.destroy = function () { + Store.prototype.destroy.call(this); + + this.pub.end(); + this.sub.end(); + this.cmd.end(); +}; + +/** + * Client constructor + * + * @api private + */ + +function Client (store, id) { + Store.Client.call(this, store, id); +}; + +/** + * Inherits from Store.Client + */ + +Client.prototype.__proto__ = Store.Client; + +/** + * Redis hash get + * + * @api private + */ + +Client.prototype.get = function (key, fn) { + this.store.cmd.hget(this.id, key, fn); + return this; +}; + +/** + * Redis hash set + * + * @api private + */ + +Client.prototype.set = function (key, value, fn) { + this.store.cmd.hset(this.id, key, value, fn); + return this; +}; + +/** + * Redis hash del + * + * @api private + */ + +Client.prototype.del = function (key, fn) { + this.store.cmd.hdel(this.id, key, fn); + return this; +}; + +/** + * Redis hash has + * + * @api private + */ + +Client.prototype.has = function (key, fn) { + this.store.cmd.hexists(this.id, key, function (err, has) { + if (err) return fn(err); + fn(null, !!has); + }); + return this; +}; + +/** + * Destroys client + * + * @param {Number} number of seconds to expire data + * @api private + */ + +Client.prototype.destroy = function (expiration) { + if ('number' != typeof expiration) { + this.store.cmd.del(this.id); + } else { + this.store.cmd.expire(this.id, expiration); + } + + return this; +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/transport.js b/NodeDrawing/node_modules/socket.io/lib/transport.js new file mode 100644 index 0000000..61f456f --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transport.js @@ -0,0 +1,534 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var parser = require('./parser'); + +/** + * Expose the constructor. + */ + +exports = module.exports = Transport; + +/** + * Transport constructor. + * + * @api public + */ + +function Transport (mng, data, req) { + this.manager = mng; + this.id = data.id; + this.disconnected = false; + this.drained = true; + this.handleRequest(req); +}; + +/** + * Access the logger. + * + * @api public + */ + +Transport.prototype.__defineGetter__('log', function () { + return this.manager.log; +}); + +/** + * Access the store. + * + * @api public + */ + +Transport.prototype.__defineGetter__('store', function () { + return this.manager.store; +}); + +/** + * Handles a request when it's set. + * + * @api private + */ + +Transport.prototype.handleRequest = function (req) { + this.log.debug('setting request', req.method, req.url); + this.req = req; + + if (req.method == 'GET') { + this.socket = req.socket; + this.open = true; + this.drained = true; + this.setHeartbeatInterval(); + + this.setHandlers(); + this.onSocketConnect(); + } +}; + +/** + * Called when a connection is first set. + * + * @api private + */ + +Transport.prototype.onSocketConnect = function () { }; + +/** + * Sets transport handlers + * + * @api private + */ + +Transport.prototype.setHandlers = function () { + var self = this; + + // we need to do this in a pub/sub way since the client can POST the message + // over a different socket (ie: different Transport instance) + this.store.subscribe('heartbeat-clear:' + this.id, function () { + self.onHeartbeatClear(); + }); + + this.store.subscribe('disconnect-force:' + this.id, function () { + self.onForcedDisconnect(); + }); + + this.store.subscribe('dispatch:' + this.id, function (packet, volatile) { + self.onDispatch(packet, volatile); + }); + + this.bound = { + end: this.onSocketEnd.bind(this) + , close: this.onSocketClose.bind(this) + , error: this.onSocketError.bind(this) + , drain: this.onSocketDrain.bind(this) + }; + + this.socket.on('end', this.bound.end); + this.socket.on('close', this.bound.close); + this.socket.on('error', this.bound.error); + this.socket.on('drain', this.bound.drain); + + this.handlersSet = true; +}; + +/** + * Removes transport handlers + * + * @api private + */ + +Transport.prototype.clearHandlers = function () { + if (this.handlersSet) { + this.store.unsubscribe('disconnect-force:' + this.id); + this.store.unsubscribe('heartbeat-clear:' + this.id); + this.store.unsubscribe('dispatch:' + this.id); + + this.socket.removeListener('end', this.bound.end); + this.socket.removeListener('close', this.bound.close); + this.socket.removeListener('error', this.bound.error); + this.socket.removeListener('drain', this.bound.drain); + } +}; + +/** + * Called when the connection dies + * + * @api private + */ + +Transport.prototype.onSocketEnd = function () { + this.end('socket end'); +}; + +/** + * Called when the connection dies + * + * @api private + */ + +Transport.prototype.onSocketClose = function (error) { + this.end(error ? 'socket error' : 'socket close'); +}; + +/** + * Called when the connection has an error. + * + * @api private + */ + +Transport.prototype.onSocketError = function (err) { + if (this.open) { + this.socket.destroy(); + this.onClose(); + } + + this.log.info('socket error ' + err.stack); +}; + +/** + * Called when the connection is drained. + * + * @api private + */ + +Transport.prototype.onSocketDrain = function () { + this.drained = true; +}; + +/** + * Called upon receiving a heartbeat packet. + * + * @api private + */ + +Transport.prototype.onHeartbeatClear = function () { + this.clearHeartbeatTimeout(); + this.setHeartbeatInterval(); +}; + +/** + * Called upon a forced disconnection. + * + * @api private + */ + +Transport.prototype.onForcedDisconnect = function () { + if (!this.disconnected) { + this.log.info('transport end by forced client disconnection'); + if (this.open) { + this.packet({ type: 'disconnect' }); + } + this.end('booted'); + } +}; + +/** + * Dispatches a packet. + * + * @api private + */ + +Transport.prototype.onDispatch = function (packet, volatile) { + if (volatile) { + this.writeVolatile(packet); + } else { + this.write(packet); + } +}; + +/** + * Sets the close timeout. + */ + +Transport.prototype.setCloseTimeout = function () { + if (!this.closeTimeout) { + var self = this; + + this.closeTimeout = setTimeout(function () { + self.log.debug('fired close timeout for client', self.id); + self.closeTimeout = null; + self.end('close timeout'); + }, this.manager.get('close timeout') * 1000); + + this.log.debug('set close timeout for client', this.id); + } +}; + +/** + * Clears the close timeout. + */ + +Transport.prototype.clearCloseTimeout = function () { + if (this.closeTimeout) { + clearTimeout(this.closeTimeout); + this.closeTimeout = null; + + this.log.debug('cleared close timeout for client', this.id); + } +}; + +/** + * Sets the heartbeat timeout + */ + +Transport.prototype.setHeartbeatTimeout = function () { + if (!this.heartbeatTimeout && this.manager.enabled('heartbeats')) { + var self = this; + + this.heartbeatTimeout = setTimeout(function () { + self.log.debug('fired heartbeat timeout for client', self.id); + self.heartbeatTimeout = null; + self.end('heartbeat timeout'); + }, this.manager.get('heartbeat timeout') * 1000); + + this.log.debug('set heartbeat timeout for client', this.id); + } +}; + +/** + * Clears the heartbeat timeout + * + * @param text + */ + +Transport.prototype.clearHeartbeatTimeout = function () { + if (this.heartbeatTimeout && this.manager.enabled('heartbeats')) { + clearTimeout(this.heartbeatTimeout); + this.heartbeatTimeout = null; + this.log.debug('cleared heartbeat timeout for client', this.id); + } +}; + +/** + * Sets the heartbeat interval. To be called when a connection opens and when + * a heartbeat is received. + * + * @api private + */ + +Transport.prototype.setHeartbeatInterval = function () { + if (!this.heartbeatInterval && this.manager.enabled('heartbeats')) { + var self = this; + + this.heartbeatInterval = setTimeout(function () { + self.heartbeat(); + self.heartbeatInterval = null; + }, this.manager.get('heartbeat interval') * 1000); + + this.log.debug('set heartbeat interval for client', this.id); + } +}; + +/** + * Clears all timeouts. + * + * @api private + */ + +Transport.prototype.clearTimeouts = function () { + this.clearCloseTimeout(); + this.clearHeartbeatTimeout(); + this.clearHeartbeatInterval(); +}; + +/** + * Sends a heartbeat + * + * @api private + */ + +Transport.prototype.heartbeat = function () { + if (this.open) { + this.log.debug('emitting heartbeat for client', this.id); + this.packet({ type: 'heartbeat' }); + this.setHeartbeatTimeout(); + } + + return this; +}; + +/** + * Handles a message. + * + * @param {Object} packet object + * @api private + */ + +Transport.prototype.onMessage = function (packet) { + var current = this.manager.transports[this.id]; + + if ('heartbeat' == packet.type) { + this.log.debug('got heartbeat packet'); + + if (current && current.open) { + current.onHeartbeatClear(); + } else { + this.store.publish('heartbeat-clear:' + this.id); + } + } else { + if ('disconnect' == packet.type && packet.endpoint == '') { + this.log.debug('got disconnection packet'); + + if (current) { + current.onForcedDisconnect(); + } else { + this.store.publish('disconnect-force:' + this.id); + } + + return; + } + + if (packet.id && packet.ack != 'data') { + this.log.debug('acknowledging packet automatically'); + + var ack = parser.encodePacket({ + type: 'ack' + , ackId: packet.id + , endpoint: packet.endpoint || '' + }); + + if (current && current.open) { + current.onDispatch(ack); + } else { + this.manager.onClientDispatch(this.id, ack); + this.store.publish('dispatch:' + this.id, ack); + } + } + + // handle packet locally or publish it + if (current) { + this.manager.onClientMessage(this.id, packet); + } else { + this.store.publish('message:' + this.id, packet); + } + } +}; + +/** + * Clears the heartbeat interval + * + * @api private + */ + +Transport.prototype.clearHeartbeatInterval = function () { + if (this.heartbeatInterval && this.manager.enabled('heartbeats')) { + clearTimeout(this.heartbeatInterval); + this.heartbeatInterval = null; + this.log.debug('cleared heartbeat interval for client', this.id); + } +}; + +/** + * Finishes the connection and makes sure client doesn't reopen + * + * @api private + */ + +Transport.prototype.disconnect = function (reason) { + this.packet({ type: 'disconnect' }); + this.end(reason); + + return this; +}; + +/** + * Closes the connection. + * + * @api private + */ + +Transport.prototype.close = function () { + if (this.open) { + this.doClose(); + this.onClose(); + } +}; + +/** + * Called upon a connection close. + * + * @api private + */ + +Transport.prototype.onClose = function () { + if (this.open) { + this.setCloseTimeout(); + this.clearHandlers(); + this.open = false; + this.manager.onClose(this.id); + this.store.publish('close', this.id); + } +}; + +/** + * Cleans up the connection, considers the client disconnected. + * + * @api private + */ + +Transport.prototype.end = function (reason) { + if (!this.disconnected) { + this.log.info('transport end'); + + var local = this.manager.transports[this.id]; + + this.close(); + this.clearTimeouts(); + this.disconnected = true; + + if (local) { + this.manager.onClientDisconnect(this.id, reason, true); + } else { + this.store.publish('disconnect:' + this.id, reason); + } + } +}; + +/** + * Signals that the transport should pause and buffer data. + * + * @api public + */ + +Transport.prototype.discard = function () { + this.log.debug('discarding transport'); + this.discarded = true; + this.clearTimeouts(); + this.clearHandlers(); + + return this; +}; + +/** + * Writes an error packet with the specified reason and advice. + * + * @param {Number} advice + * @param {Number} reason + * @api public + */ + +Transport.prototype.error = function (reason, advice) { + this.packet({ + type: 'error' + , reason: reason + , advice: advice + }); + + this.log.warn(reason, advice ? ('client should ' + advice) : ''); + this.end('error'); +}; + +/** + * Write a packet. + * + * @api public + */ + +Transport.prototype.packet = function (obj) { + return this.write(parser.encodePacket(obj)); +}; + +/** + * Writes a volatile message. + * + * @api private + */ + +Transport.prototype.writeVolatile = function (msg) { + if (this.open) { + if (this.drained) { + this.write(msg); + } else { + this.log.debug('ignoring volatile packet, buffer not drained'); + } + } else { + this.log.debug('ignoring volatile packet, transport not open'); + } +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/transports/flashsocket.js b/NodeDrawing/node_modules/socket.io/lib/transports/flashsocket.js new file mode 100644 index 0000000..48b3d95 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transports/flashsocket.js @@ -0,0 +1,102 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ +var WebSocket = require('./websocket'); + +/** + * Export the constructor. + */ + +exports = module.exports = FlashSocket; + +/** + * The FlashSocket transport is just a proxy + * for WebSocket connections. + * + * @api public + */ + +function FlashSocket (mng, data, req) { + WebSocket.call(this, mng, data, req); +} + +/** + * Inherits from WebSocket. + */ + +FlashSocket.prototype.__proto__ = WebSocket.prototype; + +/** + * Transport name + * + * @api public + */ + +FlashSocket.prototype.name = 'flashsocket'; + +/** + * Listens for new configuration changes of the Manager + * this way we can enable and disable the flash server. + * + * @param {Manager} Manager instance. + * @api private + */ + +var server; + +FlashSocket.init = function (manager) { + function create () { + server = require('policyfile').createServer({ + log: function(msg){ + manager.log.info(msg.toLowerCase()); + } + }, manager.get('origins')); + + server.on('close', function (e) { + server = null; + }); + + server.listen(manager.get('flash policy port'), manager.server); + + manager.flashPolicyServer = server; + } + + // listen for origin changes, so we can update the server + manager.on('set:origins', function (value, key) { + if (!server) return; + + // update the origins and compile a new response buffer + server.origins = Array.isArray(value) ? value : [value]; + server.compile(); + }); + + // destory the server and create a new server + manager.on('set:flash policy port', function (value, key) { + var transports = manager.get('transports'); + + if (server && server.port !== value && ~transports.indexOf('flashsocket')) { + // destroy the server and rebuild it on a new port + server.close(); + create(); + } + }); + + // only start the server + manager.on('set:transports', function (value, key){ + if (!server && ~manager.get('transports').indexOf('flashsocket')) { + create(); + } + }); + + // check if we need to initialize at start + if (~manager.get('transports').indexOf('flashsocket')){ + create(); + } +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/transports/htmlfile.js b/NodeDrawing/node_modules/socket.io/lib/transports/htmlfile.js new file mode 100644 index 0000000..6bbac75 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transports/htmlfile.js @@ -0,0 +1,82 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPTransport = require('./http'); + +/** + * Export the constructor. + */ + +exports = module.exports = HTMLFile; + +/** + * HTMLFile transport constructor. + * + * @api public + */ + +function HTMLFile (mng, data, req) { + HTTPTransport.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +HTMLFile.prototype.__proto__ = HTTPTransport.prototype; + +/** + * Transport name + * + * @api public + */ + +HTMLFile.prototype.name = 'htmlfile'; + +/** + * Handles the request. + * + * @api private + */ + +HTMLFile.prototype.handleRequest = function (req) { + HTTPTransport.prototype.handleRequest.call(this, req); + + if (req.method == 'GET') { + req.res.writeHead(200, { + 'Content-Type': 'text/html' + , 'Connection': 'keep-alive' + , 'Transfer-Encoding': 'chunked' + }); + + req.res.write( + '' + + '' + + new Array(174).join(' ') + ); + } +}; + +/** + * Performs the write. + * + * @api private + */ + +HTMLFile.prototype.write = function (data) { + data = ''; + + if (this.response.write(data)) { + this.drained = true; + } + + this.log.debug(this.name + ' writing', data); +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/transports/http-polling.js b/NodeDrawing/node_modules/socket.io/lib/transports/http-polling.js new file mode 100644 index 0000000..c71fc9c --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transports/http-polling.js @@ -0,0 +1,135 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPTransport = require('./http'); + +/** + * Exports the constructor. + */ + +exports = module.exports = HTTPPolling; + +/** + * HTTP polling constructor. + * + * @api public. + */ + +function HTTPPolling (mng, data, req) { + HTTPTransport.call(this, mng, data, req); +}; + +/** + * Inherits from HTTPTransport. + * + * @api public. + */ + +HTTPPolling.prototype.__proto__ = HTTPTransport.prototype; + +/** + * Transport name + * + * @api public + */ + +HTTPPolling.prototype.name = 'httppolling'; + +/** + * Removes heartbeat timeouts for polling. + */ + +HTTPPolling.prototype.setHeartbeatInterval = function () { + return this; +}; + +/** + * Handles a request + * + * @api private + */ + +HTTPPolling.prototype.handleRequest = function (req) { + HTTPTransport.prototype.handleRequest.call(this, req); + + if (req.method == 'GET') { + var self = this; + + this.pollTimeout = setTimeout(function () { + self.packet({ type: 'noop' }); + self.log.debug(self.name + ' closed due to exceeded duration'); + }, this.manager.get('polling duration') * 1000); + + this.log.debug('setting poll timeout'); + } +}; + +/** + * Clears polling timeout + * + * @api private + */ + +HTTPPolling.prototype.clearPollTimeout = function () { + if (this.pollTimeout) { + clearTimeout(this.pollTimeout); + this.pollTimeout = null; + this.log.debug('clearing poll timeout'); + } + + return this; +}; + +/** + * Override clear timeouts to clear the poll timeout + * + * @api private + */ + +HTTPPolling.prototype.clearTimeouts = function () { + HTTPTransport.prototype.clearTimeouts.call(this); + + this.clearPollTimeout(); +}; + +/** + * doWrite to clear poll timeout + * + * @api private + */ + +HTTPPolling.prototype.doWrite = function () { + this.clearPollTimeout(); +}; + +/** + * Performs a write. + * + * @api private. + */ + +HTTPPolling.prototype.write = function (data, close) { + this.doWrite(data); + this.response.end(); + this.onClose(); +}; + +/** + * Override end. + * + * @api private + */ + +HTTPPolling.prototype.end = function () { + this.clearPollTimeout(); + return HTTPTransport.prototype.end.call(this); +}; + diff --git a/NodeDrawing/node_modules/socket.io/lib/transports/http.js b/NodeDrawing/node_modules/socket.io/lib/transports/http.js new file mode 100644 index 0000000..cbf4e26 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transports/http.js @@ -0,0 +1,111 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var Transport = require('../transport') + , parser = require('../parser') + , qs = require('querystring'); + +/** + * Export the constructor. + */ + +exports = module.exports = HTTPTransport; + +/** + * HTTP interface constructor. For all non-websocket transports. + * + * @api public + */ + +function HTTPTransport (mng, data, req) { + Transport.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +HTTPTransport.prototype.__proto__ = Transport.prototype; + +/** + * Handles a request. + * + * @api private + */ + +HTTPTransport.prototype.handleRequest = function (req) { + if (req.method == 'POST') { + var buffer = '' + , res = req.res + , origin = req.headers.origin + , headers = { 'Content-Length': 1 } + , self = this; + + req.on('data', function (data) { + buffer += data; + }); + + req.on('end', function () { + res.writeHead(200, headers); + res.end('1'); + + self.onData(self.postEncoded ? qs.parse(buffer).d : buffer); + }); + + if (origin) { + // https://developer.mozilla.org/En/HTTP_Access_Control + headers['Access-Control-Allow-Origin'] = '*'; + + if (req.headers.cookie) { + headers['Access-Control-Allow-Credentials'] = 'true'; + } + } + } else { + this.response = req.res; + + Transport.prototype.handleRequest.call(this, req); + } +}; + +/** + * Handles data payload. + * + * @api private + */ + +HTTPTransport.prototype.onData = function (data) { + var messages = parser.decodePayload(data); + + for (var i = 0, l = messages.length; i < l; i++) { + this.log.debug(this.name + ' received data packet', data); + this.onMessage(messages[i]); + } +}; + +/** + * Closes the request-response cycle + * + * @api private + */ + +HTTPTransport.prototype.doClose = function () { + this.response.end(); +}; + +/** + * Writes a payload of messages + * + * @api private + */ + +HTTPTransport.prototype.payload = function (msgs) { + this.write(parser.encodePayload(msgs)); +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/transports/index.js b/NodeDrawing/node_modules/socket.io/lib/transports/index.js new file mode 100644 index 0000000..b865559 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transports/index.js @@ -0,0 +1,12 @@ + +/** + * Export transports. + */ + +module.exports = { + websocket: require('./websocket') + , flashsocket: require('./flashsocket') + , htmlfile: require('./htmlfile') + , 'xhr-polling': require('./xhr-polling') + , 'jsonp-polling': require('./jsonp-polling') +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/transports/jsonp-polling.js b/NodeDrawing/node_modules/socket.io/lib/transports/jsonp-polling.js new file mode 100644 index 0000000..86a23f0 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transports/jsonp-polling.js @@ -0,0 +1,78 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPPolling = require('./http-polling'); + +/** + * Export the constructor. + */ + +exports = module.exports = JSONPPolling; + +/** + * JSON-P polling transport. + * + * @api public + */ + +function JSONPPolling (mng, data, req) { + HTTPPolling.call(this, mng, data, req); + + this.head = 'io.j[0]('; + this.foot = ');'; + + if (data.query.i) { + this.head = 'io.j[' + data.query.i + ']('; + } +}; + +/** + * Inherits from Transport. + */ + +JSONPPolling.prototype.__proto__ = HTTPPolling.prototype; + +/** + * Transport name + * + * @api public + */ + +JSONPPolling.prototype.name = 'jsonppolling'; + +/** + * Make sure POST are decoded. + */ + +JSONPPolling.prototype.postEncoded = true; + +/** + * Performs the write. + * + * @api private + */ + +JSONPPolling.prototype.doWrite = function (data) { + HTTPPolling.prototype.doWrite.call(this); + + var data = data === undefined + ? '' : this.head + JSON.stringify(data) + this.foot; + + this.response.writeHead(200, { + 'Content-Type': 'text/javascript; charset=UTF-8' + , 'Content-Length': Buffer.byteLength(data) + , 'Connection': 'Keep-Alive' + , 'X-XSS-Protection': '0' + }); + + this.response.write(data); + this.log.debug(this.name + ' writing', data); +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/transports/websocket.js b/NodeDrawing/node_modules/socket.io/lib/transports/websocket.js new file mode 100644 index 0000000..41f90dc --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transports/websocket.js @@ -0,0 +1,350 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var Transport = require('../transport') + , EventEmitter = process.EventEmitter + , crypto = require('crypto') + , parser = require('../parser'); + +/** + * Export the constructor. + */ + +exports = module.exports = WebSocket; + +/** + * HTTP interface constructor. Interface compatible with all transports that + * depend on request-response cycles. + * + * @api public + */ + +function WebSocket (mng, data, req) { + // parser + var self = this; + + this.parser = new Parser(); + this.parser.on('data', function (packet) { + self.log.debug(self.name + ' received data packet', packet); + self.onMessage(parser.decodePacket(packet)); + }); + this.parser.on('close', function () { + self.end(); + }); + this.parser.on('error', function () { + self.end(); + }); + + Transport.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +WebSocket.prototype.__proto__ = Transport.prototype; + +/** + * Transport name + * + * @api public + */ + +WebSocket.prototype.name = 'websocket'; + +/** + * Called when the socket connects. + * + * @api private + */ + +WebSocket.prototype.onSocketConnect = function () { + var self = this; + + this.socket.setNoDelay(true); + + this.buffer = true; + this.buffered = []; + + if (this.req.headers.upgrade !== 'WebSocket') { + this.log.warn(this.name + ' connection invalid'); + this.end(); + return; + } + + var origin = this.req.headers.origin + , location = (this.socket.encrypted ? 'wss' : 'ws') + + '://' + this.req.headers.host + this.req.url + , waitingForNonce = false; + + if (this.req.headers['sec-websocket-key1']) { + // If we don't have the nonce yet, wait for it (HAProxy compatibility). + if (! (this.req.head && this.req.head.length >= 8)) { + waitingForNonce = true; + } + + var headers = [ + 'HTTP/1.1 101 WebSocket Protocol Handshake' + , 'Upgrade: WebSocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Origin: ' + origin + , 'Sec-WebSocket-Location: ' + location + ]; + + if (this.req.headers['sec-websocket-protocol']){ + headers.push('Sec-WebSocket-Protocol: ' + + this.req.headers['sec-websocket-protocol']); + } + } else { + var headers = [ + 'HTTP/1.1 101 Web Socket Protocol Handshake' + , 'Upgrade: WebSocket' + , 'Connection: Upgrade' + , 'WebSocket-Origin: ' + origin + , 'WebSocket-Location: ' + location + ]; + } + + try { + this.socket.write(headers.concat('', '').join('\r\n')); + this.socket.setTimeout(0); + this.socket.setNoDelay(true); + this.socket.setEncoding('utf8'); + } catch (e) { + this.end(); + return; + } + + if (waitingForNonce) { + this.socket.setEncoding('binary'); + } else if (this.proveReception(headers)) { + self.flush(); + } + + var headBuffer = ''; + + this.socket.on('data', function (data) { + if (waitingForNonce) { + headBuffer += data; + + if (headBuffer.length < 8) { + return; + } + + // Restore the connection to utf8 encoding after receiving the nonce + self.socket.setEncoding('utf8'); + waitingForNonce = false; + + // Stuff the nonce into the location where it's expected to be + self.req.head = headBuffer.substr(0, 8); + headBuffer = ''; + + if (self.proveReception(headers)) { + self.flush(); + } + + return; + } + + self.parser.add(data); + }); +}; + +/** + * Writes to the socket. + * + * @api private + */ + +WebSocket.prototype.write = function (data) { + if (this.open) { + this.drained = false; + + if (this.buffer) { + this.buffered.push(data); + return this; + } + + var length = Buffer.byteLength(data) + , buffer = new Buffer(2 + length); + + buffer.write('\u0000', 'binary'); + buffer.write(data, 1, 'utf8'); + buffer.write('\uffff', 1 + length, 'binary'); + + try { + if (this.socket.write(buffer)) { + this.drained = true; + } + } catch (e) { + this.end(); + } + + this.log.debug(this.name + ' writing', data); + } +}; + +/** + * Flushes the internal buffer + * + * @api private + */ + +WebSocket.prototype.flush = function () { + this.buffer = false; + + for (var i = 0, l = this.buffered.length; i < l; i++) { + this.write(this.buffered.splice(0, 1)[0]); + } +}; + +/** + * Finishes the handshake. + * + * @api private + */ + +WebSocket.prototype.proveReception = function (headers) { + var self = this + , k1 = this.req.headers['sec-websocket-key1'] + , k2 = this.req.headers['sec-websocket-key2']; + + if (k1 && k2){ + var md5 = crypto.createHash('md5'); + + [k1, k2].forEach(function (k) { + var n = parseInt(k.replace(/[^\d]/g, '')) + , spaces = k.replace(/[^ ]/g, '').length; + + if (spaces === 0 || n % spaces !== 0){ + self.log.warn('Invalid ' + self.name + ' key: "' + k + '".'); + self.end(); + return false; + } + + n /= spaces; + + md5.update(String.fromCharCode( + n >> 24 & 0xFF, + n >> 16 & 0xFF, + n >> 8 & 0xFF, + n & 0xFF)); + }); + + md5.update(this.req.head.toString('binary')); + + try { + this.socket.write(md5.digest('binary'), 'binary'); + } catch (e) { + this.end(); + } + } + + return true; +}; + +/** + * Writes a payload. + * + * @api private + */ + +WebSocket.prototype.payload = function (msgs) { + for (var i = 0, l = msgs.length; i < l; i++) { + this.write(msgs[i]); + } + + return this; +}; + +/** + * Closes the connection. + * + * @api private + */ + +WebSocket.prototype.doClose = function () { + this.socket.end(); +}; + +/** + * WebSocket parser + * + * @api public + */ + +function Parser () { + this.buffer = ''; + this.i = 0; +}; + +/** + * Inherits from EventEmitter. + */ + +Parser.prototype.__proto__ = EventEmitter.prototype; + +/** + * Adds data to the buffer. + * + * @api public + */ + +Parser.prototype.add = function (data) { + this.buffer += data; + this.parse(); +}; + +/** + * Parses the buffer. + * + * @api private + */ + +Parser.prototype.parse = function () { + for (var i = this.i, chr, l = this.buffer.length; i < l; i++){ + chr = this.buffer[i]; + + if (this.buffer.length == 2 && this.buffer[1] == '\u0000') { + this.emit('close'); + this.buffer = ''; + this.i = 0; + return; + } + + if (i === 0){ + if (chr != '\u0000') + this.error('Bad framing. Expected null byte as first frame'); + else + continue; + } + + if (chr == '\ufffd'){ + this.emit('data', this.buffer.substr(1, i - 1)); + this.buffer = this.buffer.substr(i + 1); + this.i = 0; + return this.parse(); + } + } +}; + +/** + * Handles an error + * + * @api private + */ + +Parser.prototype.error = function (reason) { + this.buffer = ''; + this.i = 0; + this.emit('error', reason); + return this; +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/transports/xhr-polling.js b/NodeDrawing/node_modules/socket.io/lib/transports/xhr-polling.js new file mode 100644 index 0000000..fee2438 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/transports/xhr-polling.js @@ -0,0 +1,72 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module requirements. + */ + +var HTTPPolling = require('./http-polling'); + +/** + * Export the constructor. + */ + +exports = module.exports = XHRPolling; + +/** + * Ajax polling transport. + * + * @api public + */ + +function XHRPolling (mng, data, req) { + HTTPPolling.call(this, mng, data, req); +}; + +/** + * Inherits from Transport. + */ + +XHRPolling.prototype.__proto__ = HTTPPolling.prototype; + +/** + * Transport name + * + * @api public + */ + +XHRPolling.prototype.name = 'xhr-polling'; + +/** + * Frames data prior to write. + * + * @api private + */ + +XHRPolling.prototype.doWrite = function (data) { + HTTPPolling.prototype.doWrite.call(this); + + var origin = this.req.headers.origin + , headers = { + 'Content-Type': 'text/plain; charset=UTF-8' + , 'Content-Length': data === undefined ? 0 : Buffer.byteLength(data) + , 'Connection': 'Keep-Alive' + }; + + if (origin) { + // https://developer.mozilla.org/En/HTTP_Access_Control + headers['Access-Control-Allow-Origin'] = '*'; + + if (this.req.headers.cookie) { + headers['Access-Control-Allow-Credentials'] = 'true'; + } + } + + this.response.writeHead(200, headers); + this.response.write(data); + this.log.debug(this.name + ' writing', data); +}; diff --git a/NodeDrawing/node_modules/socket.io/lib/util.js b/NodeDrawing/node_modules/socket.io/lib/util.js new file mode 100644 index 0000000..25f31f2 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/lib/util.js @@ -0,0 +1,25 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +/** + * Converts an enumerable to an array. + * + * @api public + */ + +exports.toArray = function (enu) { + var arr = []; + + for (var i = 0, l = enu.length; i < l; i++) + arr.push(enu[i]); + + return arr; +}; diff --git a/NodeDrawing/node_modules/socket.io/package.json b/NodeDrawing/node_modules/socket.io/package.json new file mode 100644 index 0000000..afe593d --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/package.json @@ -0,0 +1,29 @@ +{ + "name": "socket.io" + , "version": "0.7.8" + , "description": "Real-time apps made cross-browser & easy with a WebSocket-like API" + , "homepage": "http://socket.io" + , "keywords": ["websocket", "socket", "realtime", "socket.io", "comet", "ajax"] + , "author": "Guillermo Rauch " + , "contributors": [ + { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" } + , { "name": "Arnout Kazemier", "email": "info@3rd-eden.com" } + , { "name": "Vladimir Dronnikov", "email": "dronnikov@gmail.com" } + ] + , "repository":{ + "type": "git" + , "url": "https://github.com/LearnBoost/Socket.IO-node.git" + } + , "dependencies": { + "socket.io-client": "0.7.5" + , "policyfile": "0.0.4" + , "redis": "0.6.6" + } + , "devDependencies": { + "expresso": "0.7.7" + , "should": "0.0.4" + , "assertvanish": "0.0.3-1" + } + , "main": "index" + , "engines": { "node": ">= 0.4.0" } +} diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/LICENSE b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/LICENSE new file mode 100644 index 0000000..f3c2eae --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2010, Peter Griess +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 node-websocket-client 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 THE COPYRIGHT HOLDER 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/NodeDrawing/node_modules/socket.io/support/node-websocket-client/Makefile b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/Makefile new file mode 100644 index 0000000..e7c849a --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/Makefile @@ -0,0 +1,22 @@ +# This makefile exists to help run tests. +# +# If TEST_UNIX is a non-empty value, runs tests for UNIX sockets. This +# functionality is not in node-websocket-server at the moment. + +.PHONY: test + +all: test test-unix + +test: + for f in `ls -1 test/test-*.js | grep -v unix` ; do \ + echo $$f ; \ + node $$f ; \ + done + +test-unix: + if [[ -n "$$TEST_UNIX" ]] ; then \ + for f in `ls -1 test/test-*.js | grep unix` ; do \ + echo $$f ; \ + node $$f ; \ + done \ + fi diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/README.md b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/README.md new file mode 100644 index 0000000..8823a5c --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/README.md @@ -0,0 +1,41 @@ +A prototype [Web Socket](http://www.whatwg.org/specs/web-socket-protocol/) +client implementation for [node.js](http://nodejs.org). + +Tested with +[miksago/node-websocket-server](http://github.com/miksago/node-websocket-server) +v1.2.00. + +Requires [nodejs](http://nodejs.org) 0.1.98 or later. + +## Installation + +Install this using `npm` as follows + + npm install websocket-client + +... or just dump `lib/websocket.js` in your `$NODE_PATH`. + +## Usage + + var sys = require('sys'); + var WebSocket = require('websocket').WebSocket; + + var ws = new WebSocket('ws://localhost:8000/biff', 'borf'); + ws.addListener('data', function(buf) { + sys.debug('Got data: ' + sys.inspect(buf)); + }); + ws.onmessage = function(m) { + sys.debug('Got message: ' + m); + } + +## API + +This supports the `send()` and `onmessage()` APIs. The `WebSocket` object will +also emit `data` events that are node `Buffer` objects, in case you want to +work with something lower-level than strings. + +## Transports + +Multiple transports are supported, indicated by the scheme provided to the +`WebSocket` constructor. `ws://` is a standard TCP-based Web Socket; +`ws+unix://` allows connection to a UNIX socket at the given path. diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js new file mode 100644 index 0000000..3bb23ba --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js @@ -0,0 +1,12 @@ +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; + +var ws = new WebSocket('ws+unix://' + process.argv[2], 'boffo'); + +ws.addListener('message', function(d) { + sys.debug('Received message: ' + d.toString('utf8')); +}); + +ws.addListener('open', function() { + ws.send('This is a message', 1); +}); diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/client.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/client.js new file mode 100644 index 0000000..259bf6e --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/client.js @@ -0,0 +1,10 @@ +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; + +var ws = new WebSocket('ws://localhost:8000/biff', 'borf'); +ws.addListener('data', function(buf) { + sys.debug('Got data: ' + sys.inspect(buf)); +}); +ws.onmessage = function(m) { + sys.debug('Got message: ' + m); +} diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js new file mode 100644 index 0000000..912be0e --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js @@ -0,0 +1,13 @@ +var sys = require('sys'); +var ws = require('websocket-server/ws'); + +var srv = ws.createServer({ debug : true}); +srv.addListener('connection', function(s) { + sys.debug('Got a connection!'); + + s._req.socket.addListener('fd', function(fd) { + sys.debug('Got an fd: ' + fd); + }); +}); + +srv.listen(process.argv[2]); diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/lib/websocket.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/lib/websocket.js new file mode 100644 index 0000000..32dd79b --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/lib/websocket.js @@ -0,0 +1,599 @@ +var assert = require('assert'); +var buffer = require('buffer'); +var crypto = require('crypto'); +var events = require('events'); +var http = require('http'); +var net = require('net'); +var urllib = require('url'); +var sys = require('sys'); + +var FRAME_NO = 0; +var FRAME_LO = 1; +var FRAME_HI = 2; + +// Values for readyState as per the W3C spec +var CONNECTING = 0; +var OPEN = 1; +var CLOSING = 2; +var CLOSED = 3; + +var debugLevel = parseInt(process.env.NODE_DEBUG, 16); +var debug = (debugLevel & 0x4) ? + function() { sys.error.apply(this, arguments); } : + function() { }; + +// Generate a Sec-WebSocket-* value +var createSecretKey = function() { + // How many spaces will we be inserting? + var numSpaces = 1 + Math.floor(Math.random() * 12); + assert.ok(1 <= numSpaces && numSpaces <= 12); + + // What is the numerical value of our key? + var keyVal = (Math.floor( + Math.random() * (4294967295 / numSpaces) + ) * numSpaces); + + // Our string starts with a string representation of our key + var s = keyVal.toString(); + + // Insert 'numChars' worth of noise in the character ranges + // [0x21, 0x2f] (14 characters) and [0x3a, 0x7e] (68 characters) + var numChars = 1 + Math.floor(Math.random() * 12); + assert.ok(1 <= numChars && numChars <= 12); + + for (var i = 0; i < numChars; i++) { + var pos = Math.floor(Math.random() * s.length + 1); + + var c = Math.floor(Math.random() * (14 + 68)); + c = (c <= 14) ? + String.fromCharCode(c + 0x21) : + String.fromCharCode((c - 14) + 0x3a); + + s = s.substring(0, pos) + c + s.substring(pos, s.length); + } + + // We shoudln't have any spaces in our value until we insert them + assert.equal(s.indexOf(' '), -1); + + // Insert 'numSpaces' worth of spaces + for (var i = 0; i < numSpaces; i++) { + var pos = Math.floor(Math.random() * (s.length - 1)) + 1; + s = s.substring(0, pos) + ' ' + s.substring(pos, s.length); + } + + assert.notEqual(s.charAt(0), ' '); + assert.notEqual(s.charAt(s.length), ' '); + + return s; +}; + +// Generate a challenge sequence +var createChallenge = function() { + var c = ''; + for (var i = 0; i < 8; i++) { + c += String.fromCharCode(Math.floor(Math.random() * 255)); + } + + return c; +}; + +// Get the value of a secret key string +// +// This strips non-digit values and divides the result by the number of +// spaces found. +var secretKeyValue = function(sk) { + var ns = 0; + var v = 0; + + for (var i = 0; i < sk.length; i++) { + var cc = sk.charCodeAt(i); + + if (cc == 0x20) { + ns++; + } else if (0x30 <= cc && cc <= 0x39) { + v = v * 10 + cc - 0x30; + } + } + + return Math.floor(v / ns); +} + +// Get the to-be-hashed value of a secret key string +// +// This takes the result of secretKeyValue() and encodes it in a big-endian +// byte string +var secretKeyHashValue = function(sk) { + var skv = secretKeyValue(sk); + + var hv = ''; + hv += String.fromCharCode((skv >> 24) & 0xff); + hv += String.fromCharCode((skv >> 16) & 0xff); + hv += String.fromCharCode((skv >> 8) & 0xff); + hv += String.fromCharCode((skv >> 0) & 0xff); + + return hv; +}; + +// Compute the secret key signature based on two secret key strings and some +// handshaking data. +var computeSecretKeySignature = function(s1, s2, hs) { + assert.equal(hs.length, 8); + + var hash = crypto.createHash('md5'); + + hash.update(secretKeyHashValue(s1)); + hash.update(secretKeyHashValue(s2)); + hash.update(hs); + + return hash.digest('binary'); +}; + +// Return a hex representation of the given binary string; used for debugging +var str2hex = function(str) { + var hexChars = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + ]; + + var out = ''; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + out += hexChars[(c & 0xf0) >>> 4]; + out += hexChars[c & 0x0f]; + out += ' '; + } + + return out.trim(); +}; + +// Get the scheme for a URL, undefined if none is found +var getUrlScheme = function(url) { + var i = url.indexOf(':'); + if (i == -1) { + return undefined; + } + + return url.substring(0, i); +}; + +// Set a constant on the given object +var setConstant = function(obj, name, value) { + Object.defineProperty(obj, name, { + get : function() { + return value; + } + }); +}; + +// WebSocket object +// +// This is intended to conform (mostly) to http://dev.w3.org/html5/websockets/ +// +// N.B. Arguments are parsed in the anonymous function at the bottom of the +// constructor. +var WebSocket = function(url, proto, opts) { + events.EventEmitter.call(this); + + // Retain a reference to our object + var self = this; + + // State of our end of the connection + var readyState = CONNECTING; + + // Whether or not the server has sent a close handshake + var serverClosed = false; + + // Our underlying net.Stream instance + var stream = undefined; + + opts = opts || { + origin : 'http://www.example.com' + }; + + // Frame parsing functions + // + // These read data from the given buffer starting at the given offset, + // looking for the end of the current frame. If found, the current frame is + // emitted and the function returns. Only a single frame is processed at a + // time. + // + // The number of bytes read to complete a frame is returned, which the + // caller is to use to advance along its buffer. If 0 is returned, no + // completed frame bytes were found, and the caller should probably enqueue + // the buffer as a continuation of the current message. If a complete frame + // is read, the function is responsible for resting 'frameType'. + + // Framing data + var frameType = FRAME_NO; + var bufs = []; + var bufsBytes = 0; + + // Frame-parsing functions + var frameFuncs = [ + // FRAME_NO + function(buf, off) { + if (buf[off] & 0x80) { + frameType = FRAME_HI; + } else { + frameType = FRAME_LO; + } + + return 1; + }, + + // FRAME_LO + function(buf, off) { + debug('frame_lo(' + sys.inspect(buf) + ', ' + off + ')'); + + // Find the first instance of 0xff, our terminating byte + for (var i = off; i < buf.length && buf[i] != 0xff; i++) + ; + + // We didn't find a terminating byte + if (i >= buf.length) { + return 0; + } + + // We found a terminating byte; collect all bytes into a single buffer + // and emit it + var mb = null; + if (bufs.length == 0) { + mb = buf.slice(off, i); + } else { + mb = new buffer.Buffer(bufsBytes + i); + + var mbOff = 0; + bufs.forEach(function(b) { + b.copy(mb, mbOff, 0, b.length); + mbOff += b.length; + }); + + assert.equal(mbOff, bufsBytes); + + // Don't call Buffer.copy() if we're coping 0 bytes. Rather + // than being a no-op, this will trigger a range violation on + // the destination. + if (i > 0) { + buf.copy(mb, mbOff, off, i); + } + + // We consumed all of the buffers that we'd been saving; clear + // things out + bufs = []; + bufsBytes = 0; + } + + process.nextTick(function() { + var b = mb; + return function() { + var m = b.toString('utf8'); + + self.emit('data', b); + self.emit('message', m); // wss compat + + if (self.onmessage) { + self.onmessage({data: m}); + } + }; + }()); + + frameType = FRAME_NO; + return i - off + 1; + }, + + // FRAME_HI + function(buf, off) { + debug('frame_hi(' + sys.inspect(buf) + ', ' + off + ')'); + + if (buf[off] !== 0) { + throw new Error('High-byte framing not supported.'); + } + + serverClosed = true; + return 1; + } + ]; + + // Handle data coming from our socket + var dataListener = function(buf) { + if (buf.length <= 0 || serverClosed) { + return; + } + + debug('dataListener(' + sys.inspect(buf) + ')'); + + var off = 0; + var consumed = 0; + + do { + if (frameType < 0 || frameFuncs.length <= frameType) { + throw new Error('Unexpected frame type: ' + frameType); + } + + assert.equal(bufs.length === 0, bufsBytes === 0); + assert.ok(off < buf.length); + + consumed = frameFuncs[frameType](buf, off); + off += consumed; + } while (!serverClosed && consumed > 0 && off < buf.length); + + if (serverClosed) { + serverCloseHandler(); + } + + if (consumed == 0) { + bufs.push(buf.slice(off, buf.length)); + bufsBytes += buf.length - off; + } + }; + + // Handle incoming file descriptors + var fdListener = function(fd) { + self.emit('fd', fd); + }; + + // Handle errors from any source (HTTP client, stream, etc) + var errorListener = function(e) { + process.nextTick(function() { + self.emit('wserror', e); + + if (self.onerror) { + self.onerror(e); + } + }); + }; + + // Finish the closing process; destroy the socket and tell the application + // that we've closed. + var finishClose = self.finishClose = function() { + readyState = CLOSED; + + if (stream) { + stream.end(); + stream.destroy(); + stream = undefined; + } + + process.nextTick(function() { + self.emit('close'); + if (self.onclose) { + self.onclose(); + } + }); + }; + + // Send a close frame to the server + var sendClose = function() { + assert.equal(OPEN, readyState); + + readyState = CLOSING; + stream.write('\xff\x00', 'binary'); + }; + + // Handle a close packet sent from the server + var serverCloseHandler = function() { + assert.ok(serverClosed); + assert.ok(readyState === OPEN || readyState === CLOSING); + + bufs = []; + bufsBytes = 0; + + // Handle state transitions asynchronously so that we don't change + // readyState before the application has had a chance to process data + // events which are already in the delivery pipeline. For example, a + // 'data' event could be delivered with a readyState of CLOSING if we + // received both frames in the same packet. + process.nextTick(function() { + if (readyState === OPEN) { + sendClose(); + } + + finishClose(); + }); + }; + + // External API + self.close = function(timeout) { + if (readyState === CONNECTING) { + // If we're still in the process of connecting, the server is not + // in a position to understand our close frame. Just nuke the + // connection and call it a day. + finishClose(); + } else if (readyState === OPEN) { + sendClose(); + + if (timeout) { + setTimeout(finishClose, timeout * 1000); + } + } + }; + + self.send = function(str, fd) { + if (readyState != OPEN) { + return; + } + + stream.write('\x00', 'binary'); + stream.write(str, 'utf8', fd); + stream.write('\xff', 'binary'); + }; + + // wss compat + self.write = self.send; + + setConstant(self, 'url', url); + + Object.defineProperty(self, 'readyState', { + get : function() { + return readyState; + } + }); + + // Connect and perform handshaking with the server + (function() { + // Parse constructor arguments + if (!url) { + throw new Error('Url and must be specified.'); + } + + // Secrets used for handshaking + var key1 = createSecretKey(); + var key2 = createSecretKey(); + var challenge = createChallenge(); + + debug( + 'key1=\'' + str2hex(key1) + '\'; ' + + 'key2=\'' + str2hex(key2) + '\'; ' + + 'challenge=\'' + str2hex(challenge) + '\'' + ); + + var httpHeaders = { + 'Connection' : 'Upgrade', + 'Upgrade' : 'WebSocket', + 'Sec-WebSocket-Key1' : key1, + 'Sec-WebSocket-Key2' : key2 + }; + if (opts.origin) { + httpHeaders['Origin'] = opts.origin; + } + if (proto) { + httpHeaders['Sec-WebSocket-Protocol'] = proto; + } + + var httpPath = '/'; + + // Create the HTTP client that we'll use for handshaking. We'll cannabalize + // its socket via the 'upgrade' event and leave it to rot. + // + // N.B. The ws+unix:// scheme makes use of the implementation detail + // that http.Client passes its constructor arguments through, + // un-inspected to net.Stream.connect(). The latter accepts a + // string as its first argument to connect to a UNIX socket. + var httpClient = undefined; + switch (getUrlScheme(url)) { + case 'ws': + var u = urllib.parse(url); + httpClient = http.createClient(u.port || 80, u.hostname); + httpPath = (u.pathname || '/') + (u.search || ''); + httpHeaders.Host = u.hostname + (u.port ? (":" + u.port) : ""); + break; + + case 'ws+unix': + var sockPath = url.substring('ws+unix://'.length, url.length); + httpClient = http.createClient(sockPath); + httpHeaders.Host = 'localhost'; + break; + + default: + throw new Error('Invalid URL scheme \'' + urlScheme + '\' specified.'); + } + + httpClient.on('upgrade', (function() { + var data = undefined; + + return function(req, s, head) { + stream = s; + + stream.on('data', function(d) { + if (d.length <= 0) { + return; + } + + if (!data) { + data = d; + } else { + var data2 = new buffer.Buffer(data.length + d.length); + + data.copy(data2, 0, 0, data.length); + d.copy(data2, data.length, 0, d.length); + + data = data2; + } + + if (data.length >= 16) { + var expected = computeSecretKeySignature(key1, key2, challenge); + var actual = data.slice(0, 16).toString('binary'); + + // Handshaking fails; we're donezo + if (actual != expected) { + debug( + 'expected=\'' + str2hex(expected) + '\'; ' + + 'actual=\'' + str2hex(actual) + '\'' + ); + + process.nextTick(function() { + // N.B. Emit 'wserror' here, as 'error' is a reserved word in the + // EventEmitter world, and gets thrown. + self.emit( + 'wserror', + new Error('Invalid handshake from server:' + + 'expected \'' + str2hex(expected) + '\', ' + + 'actual \'' + str2hex(actual) + '\'' + ) + ); + + if (self.onerror) { + self.onerror(); + } + + finishClose(); + }); + } + + // Un-register our data handler and add the one to be used + // for the normal, non-handshaking case. If we have extra + // data left over, manually fire off the handler on + // whatever remains. + // + // XXX: This is lame. We should only remove the listeners + // that we added. + httpClient.removeAllListeners('upgrade'); + stream.removeAllListeners('data'); + stream.on('data', dataListener); + + readyState = OPEN; + + process.nextTick(function() { + self.emit('open'); + + if (self.onopen) { + self.onopen(); + } + }); + + // Consume any leftover data + if (data.length > 16) { + stream.emit('data', data.slice(16, data.length)); + } + } + }); + stream.on('fd', fdListener); + stream.on('error', errorListener); + stream.on('close', function() { + errorListener(new Error('Stream closed unexpectedly.')); + }); + + stream.emit('data', head); + }; + })()); + httpClient.on('error', function(e) { + httpClient.end(); + errorListener(e); + }); + + var httpReq = httpClient.request(httpPath, httpHeaders); + + httpReq.write(challenge, 'binary'); + httpReq.end(); + })(); +}; +sys.inherits(WebSocket, events.EventEmitter); +exports.WebSocket = WebSocket; + +// Add some constants to the WebSocket object +setConstant(WebSocket.prototype, 'CONNECTING', CONNECTING); +setConstant(WebSocket.prototype, 'OPEN', OPEN); +setConstant(WebSocket.prototype, 'CLOSING', CLOSING); +setConstant(WebSocket.prototype, 'CLOSED', CLOSED); + +// vim:ts=4 sw=4 et diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/package.json b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/package.json new file mode 100644 index 0000000..c6e221f --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/package.json @@ -0,0 +1,22 @@ +{ + "name" : "websocket-client", + "version" : "1.0.0", + "description" : "An HTML5 Web Sockets client", + "author" : "Peter Griess ", + "engines" : { + "node" : ">=0.1.98" + }, + "repositories" : [ + { + "type" : "git", + "url" : "http://github.com/pgriess/node-websocket-client.git" + } + ], + "licenses" : [ + { + "type" : "BSD", + "url" : "http://github.com/pgriess/node-websocket-client/blob/master/LICENSE" + } + ], + "main" : "./lib/websocket" +} diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-basic.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-basic.js new file mode 100644 index 0000000..f010424 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-basic.js @@ -0,0 +1,68 @@ +// Verify that we can connect to a WebSocket server, exchange messages, and +// shut down cleanly. + +var assert = require('assert'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws/server').Server; + +var PORT = 1024 + Math.floor(Math.random() * 4096); +var C_MSG = 'Client test: ' + (Math.random() * 100); +var S_MSG = 'Server test: ' + (Math.random() * 100); + +var serverGotConnection = false; +var clientGotOpen = false; +var clientGotData = false; +var clientGotMessage = false; +var serverGotMessage = false; +var serverGotClose = false; +var clientGotClose = false; + +var wss = new WebSocketServer(); +wss.listen(PORT, 'localhost'); +wss.on('connection', function(c) { + serverGotConnection = true; + + c.on('message', function(m) { + assert.equal(m, C_MSG); + serverGotMessage = true; + + c.close(); + }); + + c.on('close', function() { + serverGotClose = true; + wss.close(); + }); + + c.write(S_MSG); +}); + +var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff'); +ws.on('open', function() { + clientGotOpen = true; +}); +ws.on('data', function(buf) { + assert.equal(typeof buf, 'object'); + assert.equal(buf.toString('utf8'), S_MSG); + + clientGotData = true; + + ws.send(C_MSG); +}); +ws.onmessage = function(m) { + assert.deepEqual(m, {data : S_MSG}); + clientGotMessage = true; +}; +ws.onclose = function() { + clientGotClose = true; +}; + +process.on('exit', function() { + assert.ok(serverGotConnection); + assert.ok(clientGotOpen); + assert.ok(clientGotData); + assert.ok(clientGotMessage); + assert.ok(serverGotMessage); + assert.ok(serverGotClose); + assert.ok(clientGotClose); +}); diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js new file mode 100644 index 0000000..76fb81f --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js @@ -0,0 +1,43 @@ +// Verify that a connection can be closed gracefully from the client. + +var assert = require('assert'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws/server').Server; + +var PORT = 1024 + Math.floor(Math.random() * 4096); +var C_MSG = 'Client test: ' + (Math.random() * 100); + +var serverGotClientMessage = false; +var clientGotServerClose = false; +var serverGotClientClose = false; + +var wss = new WebSocketServer(); +wss.listen(PORT, 'localhost'); +wss.on('connection', function(c) { + c.on('message', function(m) { + assert.equal(m, C_MSG); + serverGotClientMessage = true; + }); + c.on('close', function() { + serverGotClientClose = true; + wss.close(); + }); +}); + +var ws = new WebSocket('ws://localhost:' + PORT); +ws.onopen = function() { + ws.send(C_MSG); + + // XXX: Add a timeout here + ws.close(5); +}; +ws.onclose = function() { + assert.equal(ws.CLOSED, ws.readyState); + clientGotServerClose = true; +}; + +process.on('exit', function() { + assert.ok(serverGotClientMessage); + assert.ok(clientGotServerClose); + assert.ok(serverGotClientClose); +}); diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js new file mode 100644 index 0000000..de896b3 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js @@ -0,0 +1,43 @@ +// Verify that some attributes of a WebSocket object are read-only. + +var assert = require('assert'); +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws/server').Server; + +var PORT = 1024 + Math.floor(Math.random() * 4096); + +var wss = new WebSocketServer(); +wss.listen(PORT, 'localhost'); +wss.on('connection', function(c) { + c.close(); + wss.close(); +}); +var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff'); +ws.on('open', function() { + assert.equal(ws.CONNECTING, 0); + try { + ws.CONNECTING = 13; + assert.equal( + ws.CONNECTING, 0, + 'Should not have been able to set read-only CONNECTING attribute' + ); + } catch (e) { + assert.equal(e.type, 'no_setter_in_callback'); + } + + assert.equal(ws.OPEN, 1); + assert.equal(ws.CLOSING, 2); + assert.equal(ws.CLOSED, 3); + + assert.equal(ws.url, 'ws://localhost:' + PORT + '/'); + try { + ws.url = 'foobar'; + assert.equal( + ws.url, 'ws://localhost:' + PORT + '/', + 'Should not have been able to set read-only url attribute' + ); + } catch (e) { + assert.equal(e.type, 'no_setter_in_callback'); + } +}); diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js new file mode 100644 index 0000000..8fcbd4c --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js @@ -0,0 +1,26 @@ +// Verify that readyState transitions are implemented correctly + +var assert = require('assert'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws/server').Server; + +var PORT = 1024 + Math.floor(Math.random() * 4096); + +var wss = new WebSocketServer(); +wss.listen(PORT, 'localhost'); +wss.on('connection', function(c) { + c.close(); +}); + +var ws = new WebSocket('ws://localhost:' + PORT); +assert.equal(ws.readyState, ws.CONNECTING); +ws.onopen = function() { + assert.equal(ws.readyState, ws.OPEN); + + ws.close(); + assert.ok(ws.readyState == ws.CLOSING); +}; +ws.onclose = function() { + assert.equal(ws.readyState, ws.CLOSED); + wss.close(); +}; diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js new file mode 100644 index 0000000..a286429 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js @@ -0,0 +1,41 @@ +// Verify that a connection can be closed gracefully from the server. + +var assert = require('assert'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws/server').Server; + +var PORT = 1024 + Math.floor(Math.random() * 4096); +var S_MSG = 'Server test: ' + (Math.random() * 100); + +var clientGotServerMessage = false; +var clientGotServerClose = false; +var serverGotClientClose = false; + +var wss = new WebSocketServer(); +wss.listen(PORT, 'localhost'); +wss.on('connection', function(c) { + c.on('close', function() { + serverGotClientClose = true; + wss.close(); + }); + + c.write(S_MSG); + c.close(); +}); + +var ws = new WebSocket('ws://localhost:' + PORT); +ws.onmessage = function(m) { + assert.deepEqual(m, {data: S_MSG}); + + clientGotServerMessage = true; +}; +ws.onclose = function() { + assert.equal(ws.CLOSED, ws.readyState); + clientGotServerClose = true; +}; + +process.on('exit', function() { + assert.ok(clientGotServerMessage); + assert.ok(clientGotServerClose); + assert.ok(serverGotClientClose); +}); diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js new file mode 100644 index 0000000..8f1c28d --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js @@ -0,0 +1,63 @@ +// Verify that both sides of the WS connection can both send and receive file +// descriptors. + +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws/server').Server; + +var PATH = path.join(__dirname, 'sock.' + process.pid); +var C_MSG = 'Client test: ' + (Math.random() * 100); +var S_MSG = 'Server test: ' + (Math.random() * 100); + +var clientReceivedData = false; +var clientReceivedFD = false; +var serverReceivedData = false; +var serverReceivedFD = false; + +var wss = new WebSocketServer(); +wss.on('listening', function() { + var ws = new WebSocket('ws+unix://' + PATH); + ws.on('data', function(d) { + assert.equal(d.toString('utf8'), S_MSG); + + clientReceivedData = true; + + ws.send(C_MSG, 1); + ws.close(); + }); + ws.on('fd', function(fd) { + assert.ok(fd >= 0); + + clientReceivedFD = true; + }); +}); +wss.on('connection', function(c) { + c.write(S_MSG, 0); + c._req.socket.on('fd', function(fd) { + assert.ok(fd >= 0); + + serverReceivedFD = true; + }); + c.on('message', function(d) { + assert.equal(d, C_MSG); + + serverReceivedData = true; + + wss.close(); + }); +}); +wss.listen(PATH); + +process.on('exit', function() { + assert.ok(clientReceivedFD); + assert.ok(clientReceivedData); + assert.ok(serverReceivedFD); + assert.ok(serverReceivedData); + + try { + fs.unlinkSync(PATH); + } catch (e) { } +}); diff --git a/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js new file mode 100644 index 0000000..5cbf094 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js @@ -0,0 +1,46 @@ +// Verify that we can connect to a server over UNIX domain sockets. + +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); +var sys = require('sys'); +var WebSocket = require('../lib/websocket').WebSocket; +var WebSocketServer = require('websocket-server/ws/server').Server; + +var PATH = path.join(__dirname, 'sock.' + process.pid); +var S_MSG = 'Server test: ' + (Math.random() * 100); + +var serverGotConnection = false; +var clientGotOpen = false; +var clientGotData = false; + +var wss = new WebSocketServer(); +wss.on('listening', function() { + var ws = new WebSocket('ws+unix://' + PATH); + ws.on('open', function() { + clientGotOpen = true; + + ws.close(); + }); + ws.on('data', function(d) { + assert.equal(d.toString('utf8'), S_MSG); + clientGotData = true; + }); +}); +wss.on('connection', function(c) { + serverGotConnection = true; + + c.write(S_MSG); + wss.close(); +}); +wss.listen(PATH); + +process.on('exit', function() { + assert.ok(serverGotConnection); + assert.ok(clientGotOpen); + assert.ok(clientGotData); + + try { + fs.unlinkSync(PATH); + } catch(e) { } +}); diff --git a/NodeDrawing/node_modules/socket.io/test/common.js b/NodeDrawing/node_modules/socket.io/test/common.js new file mode 100644 index 0000000..e658f72 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/common.js @@ -0,0 +1,244 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var io = require('socket.io') + , parser = io.parser + , http = require('http') + , https = require('https') + , WebSocket = require('../support/node-websocket-client/lib/websocket').WebSocket; + +/** + * Exports. + */ + +var should = module.exports = require('should'); + +should.HTTPClient = HTTPClient; + +/** + * Client utility. + * + * @api publiC + */ + +function HTTPClient (port) { + this.port = port; + this.agent = new http.Agent({ + host: 'localhost' + , port: port + }); +}; + +/** + * Issue a request + * + * @api private + */ + +HTTPClient.prototype.request = function (path, opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + opts = opts || {}; + opts.agent = this.agent; + opts.host = 'localhost'; + opts.port = this.port; + opts.path = path.replace(/{protocol}/g, io.protocol); + + opts.headers = opts.headers || {}; + opts.headers.Host = 'localhost'; + opts.headers.Connection = 'keep-alive'; + + var req = http.request(opts, function (res) { + if (false === opts.buffer) + return fn && fn(res); + + var buf = ''; + + res.on('data', function (chunk) { + buf += chunk; + }); + + res.on('end', function () { + fn && fn(res, opts.parse ? opts.parse(buf) : buf); + }); + }); + + req.on('error', function (err) { }); + + if (undefined !== opts.data) + req.write(opts.data); + + req.end(); + + return req; +}; + +/** + * Terminates the client and associated connections. + * + * @api public + */ + +HTTPClient.prototype.end = function () { + this.agent.sockets.forEach(function (socket) { + socket.end(); + }); +}; + +/** + * Issue a GET request + * + * @api public + */ + +HTTPClient.prototype.get = function (path, opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + opts = opts || {}; + opts.method = 'GET'; + + // override the parser for transport requests + if (/\/(xhr-polling|htmlfile|jsonp-polling)\//.test(path)) { + // parser that might be necessary for transport-specific framing + var transportParse = opts.parse; + opts.parse = function (data) { + if (data === '') return data; + + data = transportParse ? transportParse(data) : data; + return parser.decodePayload(data); + }; + } else { + opts.parse = undefined; + } + + return this.request(path, opts, fn); +}; + +/** + * Issue a POST request + * + * @api private + */ + +HTTPClient.prototype.post = function (path, data, opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + opts = opts || {}; + opts.method = 'POST'; + opts.data = data; + + return this.request(path, opts, fn); +}; + +/** + * Performs a handshake (GET) request + * + * @api private + */ + +HTTPClient.prototype.handshake = function (opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + return this.get('/socket.io/{protocol}', opts, function (res, data) { + fn && fn.apply(null, data.split(':')); + }); +}; + +/** + * Generates a new client for the given port. + * + * @api private + */ + +client = function (port) { + return new HTTPClient(port); +}; + +/** + * Create a socket.io server. + */ + +create = function (cl) { + console.log(''); + var manager = io.listen(cl.port); + manager.set('client store expiration', 0); + return manager; +}; + +/** + * WebSocket socket.io client. + * + * @api private + */ + +function WSClient (port, sid) { + this.sid = sid; + this.port = port; + + WebSocket.call( + this + , 'ws://localhost:' + port + '/socket.io/' + + io.protocol + '/websocket/' + sid + ); +}; + +/** + * Inherits from WebSocket. + */ + +WSClient.prototype.__proto__ = WebSocket.prototype; + +/** + * Overrides message event emission. + * + * @api private + */ + +WSClient.prototype.emit = function (name) { + var args = arguments; + + if (name == 'message' || name == 'data') { + args[1] = parser.decodePacket(args[1].toString()); + } + + return WebSocket.prototype.emit.apply(this, arguments); +}; + +/** + * Writes a packet + */ + +WSClient.prototype.packet = function (pack) { + this.write(parser.encodePacket(pack)); + return this; +}; + +/** + * Creates a websocket client. + * + * @api public + */ + +websocket = function (cl, sid) { + return new WSClient(cl.port, sid); +}; diff --git a/NodeDrawing/node_modules/socket.io/test/fixtures/cert.crt b/NodeDrawing/node_modules/socket.io/test/fixtures/cert.crt new file mode 100644 index 0000000..5883cd4 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/fixtures/cert.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAMUSOvlaeyQHMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTAxMTE2MDkzMjQ5WhcNMTMxMTE1MDkzMjQ5WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEVwfPQQp4X +wtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+1FAE0c5o +exPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404WthquTqg +S7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy25IyBK3QJ +c+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWAQsqW+COL +0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABo1AwTjAdBgNVHQ4EFgQUDnV4d6mD +tOnluLoCjkUHTX/n4agwHwYDVR0jBBgwFoAUDnV4d6mDtOnluLoCjkUHTX/n4agw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAFwV4MQfTo+qMv9JMiyno +IEiqfOz4RgtmBqRnXUffcjS2dhc7/z+FPZnM79Kej8eLHoVfxCyWRHFlzm93vEdv +wxOCrD13EDOi08OOZfxWyIlCa6Bg8cMAKqQzd2OvQOWqlRWBTThBJIhWflU33izX +Qn5GdmYqhfpc+9ZHHGhvXNydtRQkdxVK2dZNzLBvBlLlRmtoClU7xm3A+/5dddeP +AQHEPtyFlUw49VYtZ3ru6KqPms7MKvcRhYLsy9rwSfuuniMlx4d0bDR7TOkw0QQS +A0N8MGQRQpzl4mw4jLzyM5d5QtuGBh2P6hPGa0YQxtI3RPT/p6ENzzBiAKXiSfzo +xw== +-----END CERTIFICATE----- diff --git a/NodeDrawing/node_modules/socket.io/test/fixtures/key.key b/NodeDrawing/node_modules/socket.io/test/fixtures/key.key new file mode 100644 index 0000000..f31ff3d --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/fixtures/key.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEV +wfPQQp4XwtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+ +1FAE0c5oexPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404 +WthquTqgS7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy2 +5IyBK3QJc+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWA +QsqW+COL0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABAoIBAGe4+9VqZfJN+dsq +8Osyuz01uQ8OmC0sAWTIqUlQgENIyf9rCJsUBlYmwR5BT6Z69XP6QhHdpSK+TiAR +XUz0EqG9HYzcxHIBaACP7j6iRoQ8R4kbbiWKo0z3WqQGIOqFjvD/mKEuQdE5mEYw +eOUCG6BnX1WY2Yr8WKd2AA/tp0/Y4d8z04u9eodMpSTbHTzYMJb5SbBN1vo6FY7q +8zSuO0BMzXlAxUsCwHsk1GQHFr8Oh3zIR7bQGtMBouI+6Lhh7sjFYsfxJboqMTBV +IKaA216M6ggHG7MU1/jeKcMGDmEfqQLQoyWp29rMK6TklUgipME2L3UD7vTyAVzz +xbVOpZkCgYEA8CXW4sZBBrSSrLR5SB+Ubu9qNTggLowOsC/kVKB2WJ4+xooc5HQo +mFhq1v/WxPQoWIxdYsfg2odlL+JclK5Qcy6vXmRSdAQ5lK9gBDKxZSYc3NwAw2HA +zyHCTK+I0n8PBYQ+yGcrxu0WqTGnlLW+Otk4CejO34WlgHwbH9bbY5UCgYEA3ZvT +C4+OoMHXlmICSt29zUrYiL33IWsR3/MaONxTEDuvgkOSXXQOl/8Ebd6Nu+3WbsSN +bjiPC/JyL1YCVmijdvFpl4gjtgvfJifs4G+QHvO6YfsYoVANk4u6g6rUuBIOwNK4 +RwYxwDc0oysp+g7tPxoSgDHReEVKJNzGBe9NGGsCgYEA4O4QP4gCEA3B9BF2J5+s +n9uPVxmiyvZUK6Iv8zP4pThTBBMIzNIf09G9AHPQ7djikU2nioY8jXKTzC3xGTHM +GJZ5m6fLsu7iH+nDvSreDSeNkTBfZqGAvoGYQ8uGE+L+ZuRfCcXYsxIOT5s6o4c3 +Dle2rVFpsuKzCY00urW796ECgYBn3go75+xEwrYGQSer6WR1nTgCV29GVYXKPooy +zmmMOT1Yw80NSkEw0pFD4cTyqVYREsTrPU0mn1sPfrOXxnGfZSVFpcR/Je9QVfQ7 +eW7GYxwfom335aqHVj10SxRqteP+UoWWnHujCPz94VRKZMakBddYCIGSan+G6YdS +7sdmwwKBgBc2qj0wvGXDF2kCLwSGfWoMf8CS1+5fIiUIdT1e/+7MfDdbmLMIFVjF +QKS3zVViXCbrG5SY6wS9hxoc57f6E2A8vcaX6zy2xkZlGHQCpWRtEM5R01OWJQaH +HsHMmQZGUQVoDm1oRkDhrTFK4K3ukc3rAxzeTZ96utOQN8/KJsTv +-----END RSA PRIVATE KEY----- diff --git a/NodeDrawing/node_modules/socket.io/test/io.test.js b/NodeDrawing/node_modules/socket.io/test/io.test.js new file mode 100644 index 0000000..adc316e --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/io.test.js @@ -0,0 +1,125 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , fs = require('fs') + , http = require('http') + , https = require('https') + , should = require('./common') + , ports = 15000; + +/** + * Test. + */ + +module.exports = { + + 'test that protocol version is present': function (done) { + sio.protocol.should.be.a('number'); + done(); + }, + + 'test that default transports are present': function (done) { + sio.Manager.defaultTransports.should.be.an.instanceof(Array); + done(); + }, + + 'test that version is present': function (done) { + sio.version.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/); + done(); + }, + + 'test listening with a port': function (done) { + var cl = client(++ports) + , io = create(cl); + + io.server.should.be.an.instanceof(http.Server); + + cl.get('/', function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('Welcome to socket.io.'); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test listening with a server': function (done) { + var server = http.createServer() + , io = sio.listen(server) + , port = ++ports + , cl = client(port); + + server.listen(port); + + cl.get('/socket.io', function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('Welcome to socket.io.'); + + cl.end(); + server.close(); + done(); + }); + }, + + 'test listening with a https server': function (done) { + var server = https.createServer({ + key: fs.readFileSync(__dirname + '/fixtures/key.key') + , cert: fs.readFileSync(__dirname + '/fixtures/cert.crt') + }, function () { }) + , io = sio.listen(server) + , port = ++ports; + + server.listen(port); + + var req = require('https').get({ + host: 'localhost' + , port: port + , path: '/socket.io' + }, function (res) { + res.statusCode.should.eql(200); + + var buf = ''; + + res.on('data', function (data) { + buf += data; + }); + + res.on('end', function () { + buf.should.eql('Welcome to socket.io.'); + + res.socket.end(); + server.close(); + done(); + }); + }); + }, + + 'test listening with no arguments listens on 80': function (done) { + try { + var io = sio.listen() + , cl = client(80); + + cl.get('/socket.io', function (res) { + res.statusCode.should.eql(200); + + cl.end(); + io.server.close(); + done(); + }); + } catch (e) { + e.should.match(/EACCES/); + done(); + } + } + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/leaks/socket.leaktest.js b/NodeDrawing/node_modules/socket.io/test/leaks/socket.leaktest.js new file mode 100644 index 0000000..8613b3c --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/leaks/socket.leaktest.js @@ -0,0 +1,54 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +require.paths.unshift(__dirname + '/../../lib'); + +var assertvanish = require('assertvanish') + , common = require('../common') + , ports = 15800; + +function resultCallback (leaks, leakedSocket) { + if (leaks) { + console.error('Leak detected'); + process.exit(1); + } else { + console.error('No leaks'); + process.exit(0); + } +}; + +/** + * Test. + */ + +var cl = client(++ports); +var io = create(cl); + +io.sockets.on('connection', function (socket) { + console.log('connected'); + + socket.on('disconnect', function() { + console.log("client gone"); + setTimeout(gc, 1000); + assertvanish(socket, 2000, {silent: true, callback: resultCallback}); + }); +}); + +setTimeout(function() { + cl.handshake(function (sid) { + var ws = websocket(cl, sid); + ws.on('open', function () { + console.log('open!'); + setTimeout(function() { + ws.close(); + }, 500); + }); + }); +}, 100); diff --git a/NodeDrawing/node_modules/socket.io/test/manager.test.js b/NodeDrawing/node_modules/socket.io/test/manager.test.js new file mode 100644 index 0000000..6b8319f --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/manager.test.js @@ -0,0 +1,646 @@ +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , http = require('http') + , should = require('./common') + , ports = 15100; + +/** + * Test. + */ + +module.exports = { + + 'test setting and getting a configuration flag': function (done) { + var port = ++ports + , io = sio.listen(http.createServer()); + + io.set('a', 'b'); + io.get('a').should.eql('b'); + + var port = ++ports + , io = sio.listen(http.createServer()); + + io.configure(function () { + io.set('a', 'b'); + io.enable('tobi'); + }); + + io.get('a').should.eql('b'); + + done(); + }, + + 'test enabling and disabling a configuration flag': function (done) { + var port = ++ports + , io = sio.listen(http.createServer()); + + io.enable('flag'); + io.enabled('flag').should.be.true; + io.disabled('flag').should.be.false; + + io.disable('flag'); + var port = ++ports + , io = sio.listen(http.createServer()); + + io.configure(function () { + io.enable('tobi'); + }); + + io.enabled('tobi').should.be.true; + + done(); + }, + + 'test configuration callbacks with envs': function (done) { + var port = ++ports + , io = sio.listen(http.createServer()); + + process.env.NODE_ENV = 'development'; + + io.configure('production', function () { + io.set('ferret', 'tobi'); + }); + + io.configure('development', function () { + io.set('ferret', 'jane'); + }); + + io.get('ferret').should.eql('jane'); + done(); + }, + + 'test configuration callbacks conserve scope': function (done) { + var port = ++ports + , io = sio.listen(http.createServer()) + , calls = 0; + + process.env.NODE_ENV = 'development'; + + io.configure(function () { + this.should.eql(io); + calls++; + }); + + io.configure('development', function () { + this.should.eql(io); + calls++; + }); + + calls.should.eql(2); + done(); + }, + + 'test configuration update notifications': function (done) { + var port = ++ports + , io = sio.listen(http.createServer()) + , calls = 0; + + io.on('set:foo', function () { + calls++; + }); + + io.set('foo', 'bar'); + io.set('baz', 'bar'); + + calls.should.eql(1); + + io.enable('foo'); + io.disable('foo'); + + calls.should.eql(3); + done(); + }, + + 'test that normal requests are still served': function (done) { + var server = http.createServer(function (req, res) { + res.writeHead(200); + res.end('woot'); + }); + + var io = sio.listen(server) + , port = ++ports + , cl = client(port); + + server.listen(ports); + + cl.get('/socket.io', function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('Welcome to socket.io.'); + + cl.get('/woot', function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('woot'); + + cl.end(); + server.close(); + done(); + }); + }); + }, + + 'test that the client is served': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + cl.get('/socket.io/socket.io.js', function (res, data) { + res.headers['content-type'].should.eql('application/javascript'); + res.headers['content-length'].should.match(/([0-9]+)/); + should.strictEqual(res.headers.etag, undefined); + + data.should.match(/XMLHttpRequest/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test that the client etag is served': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.enable('browser client etag'); + }); + + cl.get('/socket.io/socket.io.js', function (res, data) { + res.headers['content-type'].should.eql('application/javascript'); + res.headers['content-length'].should.match(/([0-9]+)/); + res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/); + + data.should.match(/XMLHttpRequest/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test that the cached client is served': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + cl.get('/socket.io/socket.io.js', function (res, data) { + res.headers['content-type'].should.eql('application/javascript'); + res.headers['content-length'].should.match(/([0-9]+)/); + should.strictEqual(res.headers.etag, undefined); + + data.should.match(/XMLHttpRequest/); + var static = sio.Manager.static; + static.cache['/socket.io.js'].content.should.match(/XMLHttpRequest/); + + cl.get('/socket.io/socket.io.js', function (res, data) { + res.headers['content-type'].should.eql('application/javascript'); + res.headers['content-length'].should.match(/([0-9]+)/); + should.strictEqual(res.headers.etag, undefined); + + data.should.match(/XMLHttpRequest/); + + cl.end(); + io.server.close(); + done(); + }); + }); + }, + + 'test that the cached client etag is served': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.enable('browser client etag'); + }); + + cl.get('/socket.io/socket.io.js', function (res, data) { + res.headers['content-type'].should.eql('application/javascript'); + res.headers['content-length'].should.match(/([0-9]+)/); + res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/); + + data.should.match(/XMLHttpRequest/); + var static = sio.Manager.static + , cache = static.cache['/socket.io.js']; + + cache.content.toString().should.match(/XMLHttpRequest/); + Buffer.isBuffer(cache.content).should.be.true; + + cl.get('/socket.io/socket.io.js', function (res, data) { + res.headers['content-type'].should.eql('application/javascript'); + res.headers['content-length'].should.match(/([0-9]+)/); + res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/); + + data.should.match(/XMLHttpRequest/); + + cl.end(); + io.server.close(); + done(); + }); + }); + }, + + 'test that the cached client sends a 304 header': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.enable('browser client etag'); + }); + + cl.get('/socket.io/socket.io.js', function (res, data) { + cl.get('/socket.io/socket.io.js', {headers:{'if-none-match':res.headers.etag}}, function (res, data) { + res.statusCode.should.eql(304); + + cl.end(); + io.server.close(); + done(); + }); + }); + }, + + 'test that client minification works': function (done) { + // server 1 + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + // server 2 + var port = ++ports + , io2 = sio.listen(port) + , cl2 = client(port); + + io.configure(function () { + io.enable('browser client minification'); + }); + + cl.get('/socket.io/socket.io.js', function (res, data) { + var length = data.length; + + cl.end(); + io.server.close(); + + cl2.get('/socket.io/socket.io.js', function (res, data) { + res.headers['content-type'].should.eql('application/javascript'); + res.headers['content-length'].should.match(/([0-9]+)/); + should.strictEqual(res.headers.etag, undefined); + + data.should.match(/XMLHttpRequest/); + data.length.should.be.greaterThan(length); + + cl2.end(); + io2.server.close(); + done(); + }); + }); + }, + + 'test that the WebSocketMain.swf is served': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + cl.get('/socket.io/static/flashsocket/WebSocketMain.swf', function (res, data) { + res.headers['content-type'].should.eql('application/x-shockwave-flash'); + res.headers['content-length'].should.match(/([0-9]+)/); + should.strictEqual(res.headers.etag, undefined); + + var static = sio.Manager.static + , cache = static.cache['/static/flashsocket/WebSocketMain.swf']; + + Buffer.isBuffer(cache.content).should.be.true; + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test that the WebSocketMainInsecure.swf is served': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + cl.get('/socket.io/static/flashsocket/WebSocketMainInsecure.swf', function (res, data) { + res.headers['content-type'].should.eql('application/x-shockwave-flash'); + res.headers['content-length'].should.match(/([0-9]+)/); + should.strictEqual(res.headers.etag, undefined); + + var static = sio.Manager.static + , cache = static.cache['/static/flashsocket/WebSocketMain.swf']; + + Buffer.isBuffer(cache.content).should.be.true; + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test that you can serve custom clients': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.set('browser client handler', function (req, res) { + res.writeHead(200, { + 'Content-Type': 'application/javascript' + , 'Content-Length': 13 + , 'ETag': '1.0' + }); + res.end('custom_client'); + }); + }); + + cl.get('/socket.io/socket.io.js', function (res, data) { + res.headers['content-type'].should.eql('application/javascript'); + res.headers['content-length'].should.eql(13); + res.headers.etag.should.eql('1.0'); + + data.should.eql('custom_client'); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test that you can disable clients': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.disable('browser client'); + }); + + cl.get('/socket.io/socket.io.js', function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('Welcome to socket.io.'); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test handshake': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + cl.get('/socket.io/{protocol}/', function (res, data) { + res.statusCode.should.eql(200); + data.should.match(/([^:]+):([0-9]+)?:([0-9]+)?:(.+)/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test handshake with unsupported protocol version': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + cl.get('/socket.io/-1/', function (res, data) { + res.statusCode.should.eql(500); + data.should.match(/Protocol version not supported/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test authorization failure in handshake': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + function auth (data, fn) { + fn(null, false); + }; + + io.set('authorization', auth); + }); + + cl.get('/socket.io/{protocol}/', function (res, data) { + res.statusCode.should.eql(403); + data.should.match(/handshake unauthorized/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test a handshake error': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + function auth (data, fn) { + fn(new Error); + }; + + io.set('authorization', auth); + }); + + cl.get('/socket.io/{protocol}/', function (res, data) { + res.statusCode.should.eql(500); + data.should.match(/handshake error/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test limiting the supported transports for a manager': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.set('transports', ['tobi', 'jane']); + }); + + cl.get('/socket.io/{protocol}/', function (res, data) { + res.statusCode.should.eql(200); + data.should.match(/([^:]+):([0-9]+)?:([0-9]+)?:tobi,jane/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test setting a custom close timeout': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.set('close timeout', 66); + }); + + cl.get('/socket.io/{protocol}/', function (res, data) { + res.statusCode.should.eql(200); + data.should.match(/([^:]+):([0-9]+)?:66?:(.*)/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test setting a custom heartbeat timeout': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.set('heartbeat timeout', 33); + }); + + cl.get('/socket.io/{protocol}/', function (res, data) { + res.statusCode.should.eql(200); + data.should.match(/([^:]+):33:([0-9]+)?:(.*)/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test disabling timeouts': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + io.configure(function () { + io.set('heartbeat timeout', null); + io.set('close timeout', ''); + }); + + cl.get('/socket.io/{protocol}/', function (res, data) { + res.statusCode.should.eql(200); + data.should.match(/([^:]+)::?:(.*)/); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test disabling heartbeats': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port) + , messages = 0 + , beat = false + , ws; + + io.configure(function () { + io.disable('heartbeats'); + io.set('heartbeat interval', .05); + io.set('heartbeat timeout', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + setTimeout(function () { + socket.disconnect(); + }, io.get('heartbeat timeout') * 1000 + 100); + + socket.on('disconnect', function (reason) { + beat.should.be.false; + + cl.end(); + ws.finishClose(); + io.server.close(); + done(); + }); + }); + + cl.get('/socket.io/{protocol}/', function (res, data) { + res.statusCode.should.eql(200); + data.should.match(/([^:]+)::[\.0-9]+:(.*)/); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('message', function (packet) { + if (++messages == 1) { + packet.type.should.eql('connect'); + } else if (packet.type == 'heartbeat'){ + beat = true; + } + }); + }); + }); + }, + + 'no duplicate room members': function (done) { + var port = ++ports + , io = sio.listen(port); + + Object.keys(io.rooms).length.should.equal(0); + + io.onJoin(123, 'foo'); + io.rooms.foo.length.should.equal(1); + + io.onJoin(123, 'foo'); + io.rooms.foo.length.should.equal(1); + + io.onJoin(124, 'foo'); + io.rooms.foo.length.should.equal(2); + + io.onJoin(124, 'foo'); + io.rooms.foo.length.should.equal(2); + + io.onJoin(123, 'bar'); + io.rooms.foo.length.should.equal(2); + io.rooms.bar.length.should.equal(1); + + io.onJoin(123, 'bar'); + io.rooms.foo.length.should.equal(2); + io.rooms.bar.length.should.equal(1); + + io.onJoin(124, 'bar'); + io.rooms.foo.length.should.equal(2); + io.rooms.bar.length.should.equal(2); + + io.onJoin(124, 'bar'); + io.rooms.foo.length.should.equal(2); + io.rooms.bar.length.should.equal(2); + + io.server.close(); + done(); + }, + + 'test passing options directly to the Manager through listen': function (done) { + var port = ++ports + , io = sio.listen(port, { resource: '/my resource', custom: 'opt' }); + + io.get('resource').should.equal('/my resource'); + io.get('custom').should.equal('opt'); + io.server.close(); + done(); + } +}; diff --git a/NodeDrawing/node_modules/socket.io/test/namespace.test.js b/NodeDrawing/node_modules/socket.io/test/namespace.test.js new file mode 100644 index 0000000..5acb9d4 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/namespace.test.js @@ -0,0 +1,247 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , should = require('./common') + , ports = 15700; + +/** + * Test. + */ + +module.exports = { + 'namespace pass no authentication': function (done) { + var cl = client(++ports) + , io = create(cl) + , ws; + + io.of('/a') + .on('connection', function (socket) { + cl.end(); + ws.finishClose(); + io.server.close() + done(); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('open', function () { + ws.packet({ + type: 'connect' + , endpoint: '/a' + }); + }) + }); + }, + + 'namespace pass authentication': function (done) { + var cl = client(++ports) + , io = create(cl) + , ws; + + io.of('/a') + .authorization(function (data, fn) { + fn(null, true); + }) + .on('connection', function (socket) { + cl.end(); + ws.finishClose(); + io.server.close() + done(); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('open', function () { + ws.packet({ + type: 'connect' + , endpoint: '/a' + }); + }) + }); + }, + + 'namespace authentication handshake data': function (done) { + var cl = client(++ports) + , io = create(cl) + , ws; + + io.of('/a') + .authorization(function (data, fn) { + data.foo = 'bar'; + fn(null, true); + }) + .on('connection', function (socket) { + (!!socket.handshake.address.address).should.be.true; + (!!socket.handshake.address.port).should.be.true; + socket.handshake.headers.host.should.equal('localhost'); + socket.handshake.headers.connection.should.equal('keep-alive'); + socket.handshake.time.should.match(/GMT/); + socket.handshake.foo.should.equal('bar'); + + cl.end(); + ws.finishClose(); + io.server.close() + done(); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('open', function () { + ws.packet({ + type: 'connect' + , endpoint: '/a' + }); + }) + }); + }, + + 'namespace fail authentication': function (done) { + var cl = client(++ports) + , io = create(cl) + , calls = 0 + , ws; + + io.of('/a') + .authorization(function (data, fn) { + fn(null, false); + }) + .on('connection', function (socket) { + throw new Error('Should not be called'); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('open', function () { + ws.packet({ + type: 'connect' + , endpoint: '/a' + }); + }); + + ws.on('message', function (data) { + if (data.endpoint == '/a') { + data.type.should.eql('error'); + data.reason.should.eql('unauthorized') + + cl.end(); + ws.finishClose(); + io.server.close() + done(); + } + }) + }); + }, + + 'broadcasting sends and emits on a namespace': function (done) { + var cl = client(++ports) + , io = create(cl) + , calls = 0 + , connect = 0 + , message = 0 + , events = 0 + , expected = 5 + , ws1 + , ws2; + + io.of('a') + .on('connection', function (socket){ + socket.broadcast.emit('b', 'test'); + socket.broadcast.json.emit('json', {foo:'bar'}); + socket.broadcast.send('foo'); + }); + + function finish () { + connect.should.equal(2); + message.should.equal(1); + events.should.equal(2); + + cl.end(); + ws1.finishClose(); + ws2.finishClose(); + io.server.close(); + done(); + } + + cl.handshake(function (sid) { + ws1 = websocket(cl, sid); + + ws1.on('open', function() { + ws1.packet({ + type: 'connect' + , endpoint: 'a' + }); + }); + + ws1.on('message', function (data) { + if (data.type === 'connect') { + ++connect; + if (++calls === expected) finish(); + } + + if (data.type === 'message') { + ++message; + if (++calls === expected) finish(); + } + + if (data.type === 'event') { + if (data.name === 'b' || data.name === 'json') ++events; + if (++calls === expected) finish(); + } + }); + + cl.handshake(function (sid) { + ws2 = websocket(cl, sid); + + ws2.on('open', function () { + ws2.packet({ + type: 'connect' + , endpoint: 'a' + }); + }); + }) + }) + }, + + 'joining rooms inside a namespace': function (done) { + var cl = client(++ports) + , io = create(cl) + , calls = 0 + , ws; + + io.of('/foo').on('connection', function (socket) { + socket.join('foo.bar'); + this.in('foo.bar').emit('baz', 'pewpew'); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + + ws.on('open', function (){ + ws.packet({ + type: 'connect' + , endpoint: '/foo' + }); + }); + + ws.on('message', function (data) { + if (data.type === 'event') { + data.name.should.equal('baz'); + + cl.end(); + ws.finishClose(); + io.server.close(); + done(); + } + }); + }) + } +}; diff --git a/NodeDrawing/node_modules/socket.io/test/parser.test.js b/NodeDrawing/node_modules/socket.io/test/parser.test.js new file mode 100644 index 0000000..9bf4d06 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/parser.test.js @@ -0,0 +1,348 @@ + +/** + * Test dependencies. + */ + +var parser = require('socket.io').parser + , decode = parser.decode + , should = require('./common'); + +/** + * Test. + */ + +module.exports = { + + 'decoding error packet': function () { + parser.decodePacket('7:::').should.eql({ + type: 'error' + , reason: '' + , advice: '' + , endpoint: '' + }); + }, + + 'decoding error packet with reason': function () { + parser.decodePacket('7:::0').should.eql({ + type: 'error' + , reason: 'transport not supported' + , advice: '' + , endpoint: '' + }); + }, + + 'decoding error packet with reason and advice': function () { + parser.decodePacket('7:::2+0').should.eql({ + type: 'error' + , reason: 'unauthorized' + , advice: 'reconnect' + , endpoint: '' + }); + }, + + 'decoding error packet with endpoint': function () { + parser.decodePacket('7::/woot').should.eql({ + type: 'error' + , reason: '' + , advice: '' + , endpoint: '/woot' + }); + }, + + 'decoding ack packet': function () { + parser.decodePacket('6:::140').should.eql({ + type: 'ack' + , ackId: '140' + , endpoint: '' + , args: [] + }); + }, + + 'decoding ack packet with args': function () { + parser.decodePacket('6:::12+["woot","wa"]').should.eql({ + type: 'ack' + , ackId: '12' + , endpoint: '' + , args: ['woot', 'wa'] + }); + }, + + 'decoding ack packet with bad json': function () { + var thrown = false; + + try { + parser.decodePacket('6:::1+{"++]').should.eql({ + type: 'ack' + , ackId: '1' + , endpoint: '' + , args: [] + }); + } catch (e) { + thrown = true; + } + + thrown.should.be.false; + }, + + 'decoding json packet': function () { + parser.decodePacket('4:::"2"').should.eql({ + type: 'json' + , endpoint: '' + , data: '2' + }); + }, + + 'decoding json packet with message id and ack data': function () { + parser.decodePacket('4:1+::{"a":"b"}').should.eql({ + type: 'json' + , id: 1 + , ack: 'data' + , endpoint: '' + , data: { a: 'b' } + }); + }, + + 'decoding an event packet': function () { + parser.decodePacket('5:::{"name":"woot"}').should.eql({ + type: 'event' + , name: 'woot' + , endpoint: '' + , args: [] + }); + }, + + 'decoding an event packet with message id and ack': function () { + parser.decodePacket('5:1+::{"name":"tobi"}').should.eql({ + type: 'event' + , id: 1 + , ack: 'data' + , endpoint: '' + , name: 'tobi' + , args: [] + }); + }, + + 'decoding an event packet with data': function () { + parser.decodePacket('5:::{"name":"edwald","args":[{"a": "b"},2,"3"]}') + .should.eql({ + type: 'event' + , name: 'edwald' + , endpoint: '' + , args: [{a: 'b'}, 2, '3'] + }); + }, + + 'decoding a message packet': function () { + parser.decodePacket('3:::woot').should.eql({ + type: 'message' + , endpoint: '' + , data: 'woot' + }); + }, + + 'decoding a message packet with id and endpoint': function () { + parser.decodePacket('3:5:/tobi').should.eql({ + type: 'message' + , id: 5 + , ack: true + , endpoint: '/tobi' + , data: '' + }); + }, + + 'decoding a heartbeat packet': function () { + parser.decodePacket('2:::').should.eql({ + type: 'heartbeat' + , endpoint: '' + }); + }, + + 'decoding a connection packet': function () { + parser.decodePacket('1::/tobi').should.eql({ + type: 'connect' + , endpoint: '/tobi' + , qs: '' + }); + }, + + 'decoding a connection packet with query string': function () { + parser.decodePacket('1::/test:?test=1').should.eql({ + type: 'connect' + , endpoint: '/test' + , qs: '?test=1' + }); + }, + + 'decoding a disconnection packet': function () { + parser.decodePacket('0::/woot').should.eql({ + type: 'disconnect' + , endpoint: '/woot' + }); + }, + + 'encoding error packet': function () { + parser.encodePacket({ + type: 'error' + , reason: '' + , advice: '' + , endpoint: '' + }).should.eql('7::'); + }, + + 'encoding error packet with reason': function () { + parser.encodePacket({ + type: 'error' + , reason: 'transport not supported' + , advice: '' + , endpoint: '' + }).should.eql('7:::0'); + }, + + 'encoding error packet with reason and advice': function () { + parser.encodePacket({ + type: 'error' + , reason: 'unauthorized' + , advice: 'reconnect' + , endpoint: '' + }).should.eql('7:::2+0'); + }, + + 'encoding error packet with endpoint': function () { + parser.encodePacket({ + type: 'error' + , reason: '' + , advice: '' + , endpoint: '/woot' + }).should.eql('7::/woot'); + }, + + 'encoding ack packet': function () { + parser.encodePacket({ + type: 'ack' + , ackId: '140' + , endpoint: '' + , args: [] + }).should.eql('6:::140'); + }, + + 'encoding ack packet with args': function () { + parser.encodePacket({ + type: 'ack' + , ackId: '12' + , endpoint: '' + , args: ['woot', 'wa'] + }).should.eql('6:::12+["woot","wa"]'); + }, + + 'encoding json packet': function () { + parser.encodePacket({ + type: 'json' + , endpoint: '' + , data: '2' + }).should.eql('4:::"2"'); + }, + + 'encoding json packet with message id and ack data': function () { + parser.encodePacket({ + type: 'json' + , id: 1 + , ack: 'data' + , endpoint: '' + , data: { a: 'b' } + }).should.eql('4:1+::{"a":"b"}'); + }, + + 'encoding an event packet': function () { + parser.encodePacket({ + type: 'event' + , name: 'woot' + , endpoint: '' + , args: [] + }).should.eql('5:::{"name":"woot"}'); + }, + + 'encoding an event packet with message id and ack': function () { + parser.encodePacket({ + type: 'event' + , id: 1 + , ack: 'data' + , endpoint: '' + , name: 'tobi' + , args: [] + }).should.eql('5:1+::{"name":"tobi"}'); + }, + + 'encoding an event packet with data': function () { + parser.encodePacket({ + type: 'event' + , name: 'edwald' + , endpoint: '' + , args: [{a: 'b'}, 2, '3'] + }).should.eql('5:::{"name":"edwald","args":[{"a":"b"},2,"3"]}'); + }, + + 'encoding a message packet': function () { + parser.encodePacket({ + type: 'message' + , endpoint: '' + , data: 'woot' + }).should.eql('3:::woot'); + }, + + 'encoding a message packet with id and endpoint': function () { + parser.encodePacket({ + type: 'message' + , id: 5 + , ack: true + , endpoint: '/tobi' + , data: '' + }).should.eql('3:5:/tobi'); + }, + + 'encoding a heartbeat packet': function () { + parser.encodePacket({ + type: 'heartbeat' + , endpoint: '' + }).should.eql('2::'); + }, + + 'encoding a connection packet': function () { + parser.encodePacket({ + type: 'connect' + , endpoint: '/tobi' + , qs: '' + }).should.eql('1::/tobi'); + }, + + 'encoding a connection packet with query string': function () { + parser.encodePacket({ + type: 'connect' + , endpoint: '/test' + , qs: '?test=1' + }).should.eql('1::/test:?test=1'); + }, + + 'encoding a disconnection packet': function () { + parser.encodePacket({ + type: 'disconnect' + , endpoint: '/woot' + }).should.eql('0::/woot'); + }, + + 'test decoding a payload': function () { + parser.decodePayload('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d' + + '\ufffd3\ufffd0::').should.eql([ + { type: 'message', data: '5', endpoint: '' } + , { type: 'message', data: '53d', endpoint: '' } + , { type: 'disconnect', endpoint: '' } + ]); + }, + + 'test encoding a payload': function () { + parser.encodePayload([ + parser.encodePacket({ type: 'message', data: '5', endpoint: '' }) + , parser.encodePacket({ type: 'message', data: '53d', endpoint: '' }) + ]).should.eql('\ufffd5\ufffd3:::5\ufffd7\ufffd3:::53d') + } + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/socket.js b/NodeDrawing/node_modules/socket.io/test/socket.js new file mode 100644 index 0000000..a700cb5 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/socket.js @@ -0,0 +1,15 @@ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , should = require('./common'); + +/** + * Test. + */ + +module.exports = { + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/stores.memory.test.js b/NodeDrawing/node_modules/socket.io/test/stores.memory.test.js new file mode 100644 index 0000000..ecf9c96 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/stores.memory.test.js @@ -0,0 +1,190 @@ + +/** + * Test dependencies + * + * @api private + */ + +var sio = require('socket.io') + , should = require('should') + , MemoryStore = sio.MemoryStore; + +/** + * Test. + */ + +module.exports = { + + 'test storing data for a client': function (done) { + var store = new MemoryStore + , client = store.client('test'); + + client.id.should.equal('test'); + + client.set('a', 'b', function (err) { + should.strictEqual(err, null); + + client.get('a', function (err, val) { + should.strictEqual(err, null); + val.should.eql('b'); + + client.has('a', function (err, has) { + should.strictEqual(err, null); + has.should.be.true; + + client.has('b', function (err, has) { + should.strictEqual(err, null); + has.should.be.false; + + client.del('a', function (err) { + should.strictEqual(err, null); + + client.has('a', function (err, has) { + should.strictEqual(err, null); + has.should.be.false; + + client.set('b', 'c', function (err) { + should.strictEqual(err, null); + + client.set('c', 'd', function (err) { + should.strictEqual(err, null); + + client.get('b', function (err, val) { + should.strictEqual(err, null); + val.should.equal('c'); + + client.get('c', function (err, val) { + should.strictEqual(err, null); + val.should.equal('d'); + + store.destroy(); + done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + 'test cleaning up clients data': function (done) { + var rand1 = Math.abs(Math.random() * Date.now() | 0) + , rand2 = Math.abs(Math.random() * Date.now() | 0); + + var store = new MemoryStore() + , client1 = store.client(rand1) + , client2 = store.client(rand2); + + client1.set('a', 'b', function (err) { + should.strictEqual(err, null); + + client2.set('c', 'd', function (err) { + should.strictEqual(err, null); + + client1.has('a', function (err, val) { + should.strictEqual(err, null); + val.should.be.true; + + client2.has('c', function (err, val) { + should.strictEqual(err, null); + val.should.be.true; + + store.destroy(); + + var newstore = new MemoryStore() + , newclient1 = newstore.client(rand1) + , newclient2 = newstore.client(rand2); + + newclient1.has('a', function (err, val) { + should.strictEqual(err, null); + val.should.be.false; + + newclient2.has('c', function (err, val) { + should.strictEqual(err, null); + val.should.be.false; + + newstore.destroy(); + done(); + }); + }); + }); + }); + }); + }); + }, + + 'test cleaning up a particular client': function (done) { + var rand1 = Math.abs(Math.random() * Date.now() | 0) + , rand2 = Math.abs(Math.random() * Date.now() | 0); + + var store = new MemoryStore() + , client1 = store.client(rand1) + , client2 = store.client(rand2); + + client1.set('a', 'b', function (err) { + should.strictEqual(err, null); + + client2.set('c', 'd', function (err) { + should.strictEqual(err, null); + + client1.has('a', function (err, val) { + should.strictEqual(err, null); + val.should.be.true; + + client2.has('c', function (err, val) { + should.strictEqual(err, null); + val.should.be.true; + + store.clients.should.have.property(rand1); + store.clients.should.have.property(rand2); + store.destroyClient(rand1); + + store.clients.should.not.have.property(rand1); + store.clients.should.have.property(rand2); + + client1.has('a', function (err, val) { + should.strictEqual(err, null); + val.should.equal(false); + + store.destroy(); + done(); + }); + }); + }); + }); + }); + }, + + 'test destroy expiration': function (done) { + var store = new MemoryStore() + , id = Math.abs(Math.random() * Date.now() | 0) + , client = store.client(id); + + client.set('a', 'b', function (err) { + should.strictEqual(err, null); + store.destroyClient(id, 1); + + setTimeout(function () { + client.get('a', function (err, val) { + should.strictEqual(err, null); + val.should.equal('b'); + }); + }, 500); + + setTimeout(function () { + client.get('a', function (err, val) { + should.strictEqual(err, null); + should.strictEqual(val, null); + + store.destroy(); + done(); + }); + }, 1900); + }); + } + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/stores.redis.test.js b/NodeDrawing/node_modules/socket.io/test/stores.redis.test.js new file mode 100644 index 0000000..69848f3 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/stores.redis.test.js @@ -0,0 +1,240 @@ + +/** + * Test dependencies + * + * @api private + */ + +var sio = require('socket.io') + , redis = require('redis') + , should = require('should') + , RedisStore = sio.RedisStore; + +/** + * Test. + */ + +module.exports = { + + 'test publishing doesnt get caught by the own store subscriber': function (done) { + var a = new RedisStore + , b = new RedisStore; + + a.subscribe('woot', function (arg) { + arg.should.equal('bb'); + a.destroy(); + b.destroy(); + done(); + }, function () { + a.publish('woot', 'aa'); + b.publish('woot', 'bb'); + }); + }, + + 'test publishing to multiple subscribers': function (done) { + var a = new RedisStore + , b = new RedisStore + , c = new RedisStore + , subscriptions = 3 + , messages = 2; + + a.subscribe('tobi', function () { + throw new Error('Shouldnt publish to itself'); + }, publish); + + function subscription (arg1, arg2, arg3) { + arg1.should.equal(1); + arg2.should.equal(2); + arg3.should.equal(3); + --messages || finish(); + } + + b.subscribe('tobi', subscription, publish); + c.subscribe('tobi', subscription, publish); + + function publish () { + --subscriptions || a.publish('tobi', 1, 2, 3); + } + + function finish () { + a.destroy(); + b.destroy(); + c.destroy(); + done(); + } + }, + + 'test storing data for a client': function (done) { + var store = new RedisStore + , rand = 'test-' + Date.now() + , client = store.client(rand); + + client.id.should.equal(rand); + + client.set('a', 'b', function (err) { + should.strictEqual(err, null); + + client.get('a', function (err, val) { + should.strictEqual(err, null); + val.should.equal('b'); + + client.has('a', function (err, has) { + should.strictEqual(err, null); + has.should.be.true; + + client.has('b', function (err, has) { + should.strictEqual(err, null); + has.should.be.false; + + client.del('a', function (err) { + should.strictEqual(err, null); + + client.has('a', function (err, has) { + should.strictEqual(err, null); + has.should.be.false; + + client.set('b', 'c', function (err) { + should.strictEqual(err, null); + + client.set('c', 'd', function (err) { + should.strictEqual(err, null); + + client.get('b', function (err, val) { + should.strictEqual(err, null); + val.should.equal('c'); + + client.get('c', function (err, val) { + should.strictEqual(err, null); + val.should.equal('d'); + + store.destroy(); + done(); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }, + + 'test cleaning up clients data': function (done) { + var rand1 = Math.abs(Math.random() * Date.now() | 0) + , rand2 = Math.abs(Math.random() * Date.now() | 0); + + var store = new RedisStore() + , client1 = store.client(rand1) + , client2 = store.client(rand2); + + client1.set('a', 'b', function (err) { + should.strictEqual(err, null); + + client2.set('c', 'd', function (err) { + should.strictEqual(err, null); + + client1.has('a', function (err, val) { + should.strictEqual(err, null); + val.should.be.true; + + client2.has('c', function (err, val) { + should.strictEqual(err, null); + val.should.be.true; + + store.destroy(); + + var newstore = new RedisStore() + , newclient1 = newstore.client(rand1) + , newclient2 = newstore.client(rand2); + + newclient1.has('a', function (err, val) { + should.strictEqual(err, null); + val.should.be.false; + + newclient2.has('c', function (err, val) { + should.strictEqual(err, null); + val.should.be.false; + + newstore.destroy(); + done(); + }); + }); + }); + }); + }); + }); + }, + + 'test cleaning up a particular client': function (done) { + var rand1 = Math.abs(Math.random() * Date.now() | 0) + , rand2 = Math.abs(Math.random() * Date.now() | 0); + + var store = new RedisStore() + , client1 = store.client(rand1) + , client2 = store.client(rand2); + + client1.set('a', 'b', function (err) { + should.strictEqual(err, null); + + client2.set('c', 'd', function (err) { + should.strictEqual(err, null); + + client1.has('a', function (err, val) { + should.strictEqual(err, null); + val.should.be.true; + + client2.has('c', function (err, val) { + should.strictEqual(err, null); + val.should.be.true; + + store.clients.should.have.property(rand1); + store.clients.should.have.property(rand2); + store.destroyClient(rand1); + + store.clients.should.not.have.property(rand1); + store.clients.should.have.property(rand2); + + client1.has('a', function (err, val) { + should.strictEqual(err, null); + val.should.equal(false); + + store.destroy(); + done(); + }); + }); + }); + }); + }); + }, + + 'test destroy expiration': function (done) { + var store = new RedisStore() + , id = Math.abs(Math.random() * Date.now() | 0) + , client = store.client(id); + + client.set('a', 'b', function (err) { + should.strictEqual(err, null); + store.destroyClient(id, 1); + + setTimeout(function () { + client.get('a', function (err, val) { + should.strictEqual(err, null); + val.should.equal('b'); + }); + }, 500); + + setTimeout(function () { + client.get('a', function (err, val) { + should.strictEqual(err, null); + should.strictEqual(val, null); + + store.destroy(); + done(); + }); + }, 2000); + }); + } + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/transports.flashsocket.test.js b/NodeDrawing/node_modules/socket.io/test/transports.flashsocket.test.js new file mode 100644 index 0000000..f554aa5 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/transports.flashsocket.test.js @@ -0,0 +1,168 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , net = require('net') + , http = require('http') + , should = require('./common') + , WebSocket = require('../support/node-websocket-client/lib/websocket').WebSocket + , WSClient = require('./transports.websocket.test') + , parser = sio.parser + , ports = 15600; + +/** + * FlashSocket client constructor. + * + * @api private + */ + +function FlashSocket (port, sid) { + this.sid = sid; + this.port = port; + + WebSocket.call( + this + , 'ws://localhost:' + port + '/socket.io/' + + sio.protocol + '/flashsocket/' + sid + ); +}; + +/** + * Inherits from WSClient. + */ + +FlashSocket.prototype.__proto__ = WebSocket.prototype; + +/** + * Creates a TCP connection to a port. + * + * @api public + */ + +function netConnection (port, callback){ + var nclient = net.createConnection(port); + + nclient.on('data', function (data) { + callback.call(nclient, null, data); + }); + + nclient.on('error', function (e){ + callback.call(nclient, e); + }); + + nclient.write('\0'); +} + +/** + * Tests. + */ + +module.exports = { + + 'flashsocket disabled by default': function (done) { + var io = sio.listen(http.createServer()); + io.get('transports').should.not.contain('flashsocket'); + done(); + }, + + 'flash policy port': function (done) { + var io = sio.listen(http.createServer()) + , port = ++ports; + + io.get('flash policy port').should.eql(843); + io.set('flash policy port', port); + io.get('flash policy port').should.eql(port); + + should.strictEqual(io.flashPolicyServer, undefined); + + netConnection(port, function (err, data){ + err.should.be.an.instanceof(Error); + err.code.should.eql('ECONNREFUSED'); + + this.destroy(); + done(); + }) + }, + + 'start flash policy': function (done) { + var io = sio.listen(http.createServer()) + , port = ++ports; + + io.set('flash policy port', port); + io.set('transports', ['flashsocket']); + + io.flashPolicyServer.should.be.a('object'); + + netConnection(port, function (err, data){ + should.strictEqual(err, null); + + data.toString().should.include.string(''); + + this.destroy(); + io.flashPolicyServer.close(); + done(); + }) + + }, + + 'change running flash server port': function (done) { + var io = sio.listen(http.createServer()) + , port = ++ports + , next = ++ports; + + io.set('flash policy port', port); + io.set('transports', ['flashsocket']); + io.set('flash policy port', next); + io.flashPolicyServer.port.should.eql(next); + + netConnection(port, function (err, data){ + err.should.be.an.instanceof(Error); + err.code.should.eql('ECONNREFUSED'); + + this.destroy(); + + // should work + netConnection(next, function (err, data){ + should.strictEqual(err, null); + + data.toString().should.include.string(''); + + this.destroy(); + io.flashPolicyServer.close(); + done(); + }); + }); + }, + + 'different origins': function(done) { + var io = sio.listen(http.createServer()) + , port = ++ports; + + io.set('flash policy port', port); + io.set('transports', ['flashsocket']); + io.set('origins', 'google.com:80'); + + var server = io.flashPolicyServer; + + server.origins.should.contain('google.com:80'); + server.origins.should.not.contain('*.*'); + + io.set('origins', ['foo.bar:80', 'socket.io:1337']); + server.origins.should.not.contain('google.com:80'); + server.origins.should.contain('foo.bar:80'); + server.origins.should.contain('socket.io:1337'); + server.buffer.toString('utf8').should.include.string('socket.io'); + + io.flashPolicyServer.close(); + done(); + } + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/transports.htmlfile.test.js b/NodeDrawing/node_modules/socket.io/test/transports.htmlfile.test.js new file mode 100644 index 0000000..a9429ab --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/transports.htmlfile.test.js @@ -0,0 +1,458 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , should = require('./common') + , HTTPClient = should.HTTPClient + , parser = sio.parser + , ports = 15300; + +/** + * HTTPClient for htmlfile transport. + */ + +function HTMLFile (port) { + HTTPClient.call(this, port); +}; + +/** + * Inhertis from HTTPClient. + */ + +HTMLFile.prototype.__proto__ = HTTPClient.prototype; + +/** + * Override GET request with streaming parser. + * + * @api public + */ + +var head = '' + , initial = '' + + '' + + new Array(174).join(' ') + +HTMLFile.prototype.data = function (path, opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + opts.buffer = false; + + return this.request(path, opts, function (res) { + var buf = '' + , messages = 0 + , state = 0; + + res.on('data', function (chunk) { + buf += chunk; + + function parse () { + switch (state) { + case 0: + if (buf.indexOf(initial) === 0) { + buf = buf.substr(initial.length); + state = 1; + } else { + break; + } + + case 1: + if (buf.indexOf(head) === 0) { + buf = buf.substr(head.length); + state = 2; + } else { + break; + } + + case 2: + if (buf.indexOf(foot) != -1) { + var data = buf.slice(0, buf.indexOf(foot)) + , obj = JSON.parse(data); + + fn(obj === '' ? obj : parser.decodePayload(obj), ++messages); + + buf = buf.substr(data.length + foot.length); + state = 1; + + parse(); + } + }; + }; + + parse(); + }); + }); +}; + +/** + * Create client for this transport. + * + * @api public + */ + +function client (port) { + return new HTMLFile(port); +}; + +/** + * Tests. + */ + +module.exports = { + + 'test that not responding to a heartbeat drops client': function (done) { + var port = ++ports + , cl = client(port) + , io = create(cl) + , beat = false; + + io.configure(function () { + io.set('heartbeat interval', .05); + io.set('heartbeat timeout', .05); + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function (reason) { + beat.should.be.true; + reason.should.eql('heartbeat timeout'); + + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) { + switch (i) { + case 1: + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + msgs[0].endpoint.should.eql(''); + break; + + case 2: + msgs.should.have.length(1); + msgs[0].type.should.eql('heartbeat'); + beat = true; + }; + }); + }); + }, + + 'test that responding to a heartbeat maintains session': function (done) { + var port = ++ports + , cl = client(port) + , io = create(cl) + , heartbeats = 0; + + io.configure(function () { + io.set('heartbeat interval', .05); + io.set('heartbeat timeout', .05); + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function (reason) { + heartbeats.should.eql(2); + reason.should.eql('heartbeat timeout'); + + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) { + switch (i) { + case 1: + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + msgs[0].endpoint.should.eql(''); + break; + + default: + msgs.should.have.length(1); + msgs[0].type.should.eql('heartbeat'); + + heartbeats++; + + if (heartbeats == 1) { + cl.post('/socket.io/{protocol}/htmlfile/' + sid, parser.encodePacket({ + type: 'heartbeat' + })); + } + } + }); + }); + }, + + 'test sending undeliverable volatile messages': function (done) { + var port = ++ports + , cl = client(port) + , io = create(cl) + , messaged = false + , s; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + messaged.should.be.false; + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function () { }); + + setTimeout(function () { + cl.end(); + + setTimeout(function () { + s.volatile.send('wooooot'); + cl = client(port); + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs) { + if (msgs && msgs.length) + messaged = true; + }); + + setTimeout(function () { + cl.end(); + }, 20); + }, 20); + }, 20); + }); + }, + + 'test sending undeliverable volatile json': function (done) { + var port = ++ports + , cl = client(port) + , io = create(cl) + , messaged = false + , s; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + messaged.should.be.false; + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function () { }); + + setTimeout(function () { + cl.end(); + + setTimeout(function () { + s.volatile.json.send(123); + + cl = client(port); + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs) { + if (msgs && msgs.length) + messaged = true; + }); + + setTimeout(function () { + cl.end(); + }, 20); + }, 20); + }, 20); + }); + }, + + 'test sending undeliverable volatile events': function (done) { + var port = ++ports + , cl = client(port) + , io = create(cl) + , messaged = false + , s; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + messaged.should.be.false; + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function () { }); + + setTimeout(function () { + cl.end(); + + setTimeout(function () { + s.volatile.emit('tobi'); + + cl = client(port); + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs) { + if (msgs && msgs.length) + messaged = true; + }); + + setTimeout(function () { + cl.end(); + }, 20); + }, 20); + }, 20); + }); + }, + + 'test sending deliverable volatile messages': function (done) { + var port = ++ports + , cl = client(port) + , io = create(cl) + , messaged = false; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.volatile.send('woot'); + + socket.on('disconnect', function () { + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) { + switch (i) { + case 1: + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + msgs[0].endpoint.should.eql(''); + break; + + case 2: + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'message' + , data: 'woot' + , endpoint: '' + }); + cl.end(); + } + }); + }); + }, + + 'test sending deliverable volatile json': function (done) { + var port = ++ports + , cl = client(port) + , io = create(cl) + , messaged = false; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.volatile.json.send(['woot']); + + socket.on('disconnect', function () { + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) { + switch (i) { + case 1: + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + msgs[0].endpoint.should.eql(''); + break; + + case 2: + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'json' + , data: ['woot'] + , endpoint: '' + }); + cl.end(); + } + }); + }); + }, + + 'test sending deliverable volatile events': function (done) { + var port = ++ports + , cl = client(port) + , io = create(cl) + , messaged = false; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.volatile.emit('aaa'); + + socket.on('disconnect', function () { + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) { + switch (i) { + case 1: + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + msgs[0].endpoint.should.eql(''); + break; + + case 2: + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'event' + , name: 'aaa' + , endpoint: '' + , args: [] + }); + cl.end(); + } + }); + }); + } + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/transports.jsonp-polling.test.js b/NodeDrawing/node_modules/socket.io/test/transports.jsonp-polling.test.js new file mode 100644 index 0000000..c087d33 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/transports.jsonp-polling.test.js @@ -0,0 +1,770 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , should = require('./common') + , qs = require('querystring') + , HTTPClient = should.HTTPClient + , parser = sio.parser + , ports = 15500; + +/** + * HTTPClient for jsonp-polling transport. + */ + +function JSONPPolling (port) { + HTTPClient.call(this, port); +}; + +/** + * Inhertis from HTTPClient. + */ + +JSONPPolling.prototype.__proto__ = HTTPClient.prototype; + +/** + * Performs a json-p (cross domain) handshake + * + * @api public + */ + +JSONPPolling.prototype.handshake = function (opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + var self = this; + + return this.get( + '/socket.io/{protocol}?jsonp=0' + , opts + , function (res, data) { + var head = 'io.j[0](' + , foot = ');'; + + data.substr(0, head.length).should.eql(head); + data.substr(-foot.length).should.eql(foot); + data = data.slice(head.length, data.length - foot.length); + + var parts = JSON.parse(data).split(':'); + + if (opts.ignoreConnect) { + return fn && fn.apply(null, parts); + } + + // expect connect packet right after handshake + self.get( + '/socket.io/{protocol}/jsonp-polling/' + parts[0] + , function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'connect', endpoint: '', qs: '' }); + + fn && fn.apply(null, parts); + } + ); + } + ); +}; + +/** + * Override GET requests. + * + * @api public + */ + +JSONPPolling.prototype.get = function (path, opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + opts = opts || {}; + + opts.parse = function (data) { + var head = 'io.j[0](' + , foot = ');'; + + if (~path.indexOf('?i=1')) { + head = 'io.j[1]('; + } + + data.substr(0, head.length).should.eql(head); + data.substr(-foot.length).should.eql(foot); + + data = data.substr(head.length, data.length - head.length - foot.length); + + return JSON.parse(data); + }; + + return HTTPClient.prototype.get.call(this, path, opts, fn); +}; + +/** + * Issue an encoded POST request + * + * @api private + */ + +JSONPPolling.prototype.post = function (path, data, opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + opts = opts || {}; + opts.method = 'POST'; + opts.data = qs.stringify({ d: data }); + + return this.request(path, opts, fn); +}; + +/** + * Create client for this transport. + * + * @api public + */ + +function client (port) { + return new JSONPPolling(port); +}; + +/** + * Test. + */ + +module.exports = { + + 'test jsonp handshake': function (done) { + var cl = client(++ports) + , io = create(cl); + + io.configure(function () { + io.set('close timeout', .05); + io.set('polling duration', 0); + }); + + function finish () { + cl.end(); + io.server.close(); + done(); + }; + + cl.handshake(function (sid) { + var total = 2; + + cl.get('/socket.io/{protocol}/jsonp-polling/tobi', function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'error' + , reason: 'client not handshaken' + , endpoint: '' + , advice: 'reconnect' + }); + + --total || finish(); + }); + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + --total || finish(); + }); + }); + }, + + 'test the connection event': function (done) { + var cl = client(++ports) + , io = create(cl) + , sid; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.id.should.eql(sid); + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + }); + }); + }, + + 'test the disconnection event after a close timeout': function (done) { + var cl = client(++ports) + , io = create(cl) + , sid; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.id.should.eql(sid); + + socket.on('disconnect', function () { + io.server.close(); + done(); + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + + setTimeout(function () { + cl.end(); + }, 10); + }); + }); + }, + + 'test the disconnection event when the client sends ?disconnect req': + function (done) { + var cl = client(++ports) + , io = create(cl) + , disconnected = false + , sid; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + disconnected = true; + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'disconnect', endpoint: '' }); + disconnected.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid + '/?disconnect'); + }); + }); + }, + + 'test the disconnection event booting a client': function (done) { + var cl = client(++ports) + , io = create(cl) + , forced = false; + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + io.server.close(); + done(); + }); + + cl.end(); + socket.disconnect(); + forced = true; + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'disconnect', endpoint: '' }); + + forced.should.be.true; + }); + }); + }, + + 'test the disconnection event with client disconnect packet': function (done) { + var cl = client(++ports) + , io = create(cl) + , sid; + + io.sockets.on('connection', function (client) { + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'disconnect' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + + client.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + }); + }); + }, + + 'test sending back data': function (done) { + var cl = client(++ports) + , io = create(cl); + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.send('woot'); + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, packs) { + packs.should.have.length(1); + packs[0].type.should.eql('message'); + packs[0].data.should.eql('woot'); + }); + }); + }, + + 'test sending a batch of messages': function (done) { + var cl = client(++ports) + , io = create(cl) + , sid; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + var messages = 0; + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePayload([ + parser.encodePacket({ type: 'message', data: 'a' }) + , parser.encodePacket({ type: 'message', data: 'b' }) + , parser.encodePacket({ type: 'disconnect' }) + ]) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + + socket.on('message', function (data) { + messages++; + + if (messages == 1) + data.should.eql('a'); + + if (messages == 2) + data.should.eql('b'); + }); + + socket.on('disconnect', function () { + messages.should.eql(2); + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + }); + }); + }, + + 'test message buffering between a response and a request': function (done) { + var cl = client(++ports) + , io = create(cl) + , messages = false + , tobi; + + io.configure(function () { + io.set('polling duration', .1); + io.set('close timeout', .2); + }); + + io.sockets.on('connection', function (socket) { + tobi = function () { + socket.send('a'); + socket.send('b'); + socket.send('c'); + }; + + socket.on('disconnect', function () { + messages.should.be.true; + + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + tobi(); + + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + msgs.should.have.length(3); + msgs[0].should.eql({ type: 'message', endpoint: '', data: 'a' }); + msgs[1].should.eql({ type: 'message', endpoint: '', data: 'b' }); + msgs[2].should.eql({ type: 'message', endpoint: '', data: 'c' }); + messages = true; + }); + }) + }); + }, + + 'test connecting to a specific endpoint': function (done) { + var cl = client(++ports) + , io = create(cl) + , connectMessage = false + , sid; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.of('/woot').on('connection', function (socket) { + connectMessage.should.be.true; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, data) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid); + + connectMessage = true; + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/woot' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + }); + }); + }, + + 'test that connecting doesnt connect to defined endpoints': function (done) { + var cl = client(++ports) + , io = create(cl) + , tobiConnected = false + , mainConnected = false + , sid; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + mainConnected = true; + + socket.on('disconnect', function () { + tobiConnected.should.be.false; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/tobi').on('connection', function () { + tobiConnected = true; + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid); + }); + }, + + 'test disconnecting a specific endpoint': function (done) { + var cl = client(++ports) + , io = create(cl) + , wootDisconnected = false + , mainDisconnected = false + , checked = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (data) { + data.should.eql('ferret'); + mainDisconnected.should.be.false; + wootDisconnected.should.be.true; + checked = true; + }); + + socket.on('disconnect', function () { + mainDisconnected = true; + checked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/woot').on('connection', function (socket) { + socket.on('disconnect', function () { + wootDisconnected = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function () { + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/woot' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'disconnect', endpoint: '/woot' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'message', data: 'ferret' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + } + ); + }); + }); + }, + + 'test that disconnecting disconnects all endpoints': function (done) { + var cl = client(++ports) + , io = create(cl) + , aDisconnected = false + , bDisconnected = false; + + io.configure(function () { + io.set('polling duration', .2); + io.set('close timeout', .2); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + setTimeout(function () { + aDisconnected.should.be.true; + bDisconnected.should.be.true; + cl.end(); + io.server.close(); + done(); + }, 50); + }); + }); + + io.of('/a').on('connection', function (socket) { + socket.on('disconnect', function (msg) { + aDisconnected = true; + }); + }); + + io.of('/b').on('connection', function (socket) { + socket.on('disconnect', function (msg) { + bDisconnected = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/b' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + }); + }); + }, + + 'test messaging a specific endpoint': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = true + , aMessaged = false + , bMessaged = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql(''); + messaged = true; + }); + + socket.on('disconnect', function () { + messaged.should.be.true; + aMessaged.should.be.true; + bMessaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/a').on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql('a'); + aMessaged = true; + }); + }); + + io.of('/b').on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql('b'); + bMessaged = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/jsonp-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'message', data: '' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'message', endpoint: '/a', data: 'a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/b' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/jsonp-polling/' + sid + , parser.encodePacket({ type: 'message', endpoint: '/b', data: 'b' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + }); + }); + } + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/transports.websocket.test.js b/NodeDrawing/node_modules/socket.io/test/transports.websocket.test.js new file mode 100644 index 0000000..4b9ff61 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/transports.websocket.test.js @@ -0,0 +1,1771 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , should = require('./common') + , parser = sio.parser + , ports = 15800; + +/** + * Tests. + */ + +module.exports = { + + 'test that not responding to a heartbeat drops client': function (done) { + var cl = client(++ports) + , io = create(cl) + , messages = 0 + , ws; + + io.configure(function () { + io.set('heartbeat interval', .05); + io.set('heartbeat timeout', .05); + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function (reason) { + beat.should.be.true; + reason.should.eql('heartbeat timeout'); + + cl.end(); + ws.finishClose(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('message', function (packet) { + if (++messages == 1) { + packet.type.should.eql('connect'); + } else { + packet.type.should.eql('heartbeat'); + beat = true; + } + }); + }); + }, + + 'test that responding to a heartbeat maintains session': function (done) { + var cl = client(++ports) + , io = create(cl) + , messages = 0 + , heartbeats = 0 + , ws; + + io.configure(function () { + io.set('heartbeat interval', .05); + io.set('heartbeat timeout', .05); + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function (reason) { + heartbeats.should.eql(2); + reason.should.eql('heartbeat timeout'); + + cl.end(); + ws.finishClose(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('message', function (packet) { + if (++messages == 1) { + packet.type.should.eql('connect'); + } else { + packet.type.should.eql('heartbeat'); + heartbeats++; + + if (heartbeats == 1) { + ws.packet({ type: 'heartbeat' }); + } + } + }); + }); + }, + + 'test sending undeliverable volatile messages': function (done) { + var cl = client(++ports) + , io = create(cl) + , messages = 0 + , messaged = false + , s; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + messaged.should.be.false; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + var ws = websocket(cl, sid); + ws.on('message', function (msg) { + msg.type.should.eql('connect'); + ws.finishClose(); + + setTimeout(function () { + s.volatile.send('ah wha wha'); + + ws = websocket(cl, sid); + ws.on('message', function () { + messaged = true; + }); + + setTimeout(function () { + ws.finishClose(); + }, 10); + }, 10); + }); + }); + }, + + 'test sending undeliverable volatile json': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false + , s; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + messaged.should.be.false; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + var ws = websocket(cl, sid); + ws.on('message', function () { + ws.finishClose(); + + setTimeout(function () { + s.volatile.json.send({ a: 'b' }); + + ws = websocket(cl, sid); + ws.on('message', function () { + messaged = true; + }); + + setTimeout(function () { + ws.finishClose(); + }, 10); + }, 10); + }); + }); + }, + + 'test sending undeliverable volatile events': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false + , s; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + messaged.should.be.false; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + var ws = websocket(cl, sid); + ws.on('message', function () { + ws.finishClose(); + + setTimeout(function () { + s.volatile.emit({ a: 'b' }); + + ws = websocket(cl, sid); + ws.on('message', function () { + messaged = true; + }); + + setTimeout(function () { + ws.finishClose(); + }, 10); + }, 10); + }); + }); + }, + + 'test sending deliverable volatile messages': function (done) { + var cl = client(++ports) + , io = create(cl) + , messages = 0 + , messaged = false; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.volatile.send('tobi'); + + socket.on('disconnect', function () { + messaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + var ws = websocket(cl, sid); + ws.on('message', function (msg) { + if (++messages == 1) { + msg.type.should.eql('connect'); + } else { + msg.should.eql({ + type: 'message' + , data: 'tobi' + , endpoint: '' + }); + messaged = true; + ws.finishClose(); + } + }); + }); + }, + + 'test sending deliverable volatile json': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.volatile.json.send([1, 2, 3]); + + socket.on('disconnect', function () { + messaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + var ws = websocket(cl, sid); + ws.on('message', function (msg) { + if (!ws.connected) { + msg.type.should.eql('connect'); + ws.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: [1, 2, 3] + , endpoint: '' + }); + messaged = true; + ws.finishClose(); + } + }); + }); + }, + + 'test sending deliverable volatile events': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.volatile.emit('tobi'); + + socket.on('disconnect', function () { + messaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + var ws = websocket(cl, sid); + ws.on('message', function (msg) { + if (!ws.connected) { + msg.type.should.eql('connect'); + ws.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'tobi' + , endpoint: '' + , args: [] + }); + messaged = true; + ws.finishClose(); + } + }); + }); + }, + + 'test sending to all clients in a namespace': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , io = create(cl1) + , messages = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections == 2) { + io.sockets.send('yup'); + } + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 2) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'message' + , data: 'yup' + , endpoint: '' + }); + + messages++; + ws1.finishClose(); + } + }); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'message' + , data: 'yup' + , endpoint: '' + }); + + messages++; + ws2.finishClose(); + } + }); + }); + }, + + 'test sending json to all clients in a namespace': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , io = create(cl1) + , messages = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections == 2) { + io.sockets.json.send({ a: 'b' }); + } + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 2) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: { a: 'b' } + , endpoint: '' + }); + + messages++; + ws1.finishClose(); + } + }); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: { a: 'b' } + , endpoint: '' + }); + + messages++; + ws2.finishClose(); + } + }); + }); + }, + + 'test emitting to all clients in a namespace': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , io = create(cl1) + , messages = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections == 2) { + io.sockets.emit('tobi', 'rapture'); + } + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 2) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'tobi' + , args: ['rapture'] + , endpoint: '' + }); + + messages++; + ws1.finishClose(); + } + }); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'tobi' + , args: ['rapture'] + , endpoint: '' + }); + + messages++; + ws2.finishClose(); + } + }); + }); + }, + + 'test sending to all clients in a room': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , joins = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections != 3) { + socket.join('woot'); + joins++; + + if (joins == 2) { + setTimeout(function () { + connections.should.eql(3); + io.sockets.in('woot').send('hahaha'); + }, 20); + } + } + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'message' + , data: 'hahaha' + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws1.finishClose(); + }, 50); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'message' + , data: 'hahaha' + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws2.finishClose(); + }, 50); + }); + + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + msg.should.eql({ + type: 'message' + , data: 'hahaha' + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws3.finishClose(); + }, 50); + }); + }, + + 'test sending json to all clients in a room': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , joins = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections != 3) { + socket.join('woot'); + joins++; + + if (joins == 2) { + setTimeout(function () { + connections.should.eql(3); + io.sockets.in('woot').json.send(123); + }, 20); + } + } + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: 123 + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws1.finishClose(); + }, 50); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: 123 + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws2.finishClose(); + }, 50); + }); + + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: 123 + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws3.finishClose(); + }, 50); + }); + }, + + 'test emitting to all clients in a room': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , joins = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections != 3) { + socket.join('woot'); + joins++; + + if (joins == 2) { + setTimeout(function () { + connections.should.eql(3); + io.sockets.in('woot').emit('locki'); + }, 20); + } + } + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'locki' + , args: [] + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws1.finishClose(); + }, 50); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'locki' + , args: [] + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws2.finishClose(); + }, 50); + }); + + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'locki' + , args: [] + , endpoint: '' + }); + + messages++; + } + }); + + setTimeout(function () { + ws3.finishClose(); + }, 50); + }); + }, + + 'test leaving a room': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , io = create(cl1) + , joins = 0 + , disconnects = 0; + + io.set('close timeout', 0); + + io.sockets.on('connection', function (socket) { + socket.join('foo'); + io.sockets.clients('foo').should.have.length(++joins); + + socket.on('disconnect', function () { + socket.leave('foo'); + socket.leave('foo'); + socket.leave('foo'); + + io.sockets.clients('foo').should.have.length(--joins); + + if (++disconnects == 2) { + io.server.close(); + cl1.end(); + cl2.end(); + done(); + } + }) + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + ws1.finishClose(); + } + }); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + ws2.finishClose(); + } + }); + }); + }, + + 'test message with broadcast flag': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.on('trigger broadcast', function () { + socket.broadcast.send('boom'); + }); + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'message' + , data: 'boom' + , endpoint: '' + }); + + messages++; + ws1.finishClose(); + } + }); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'message' + , data: 'boom' + , endpoint: '' + }); + + messages++; + ws2.finishClose(); + } + }); + }); + + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('open', function () { + ws3.packet({ + type: 'event' + , name: 'trigger broadcast' + , endpoint: '' + }); + + setTimeout(function () { + ws3.finishClose(); + }, 50); + }); + + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + throw new Error('we shouldnt get a message here'); + } + }); + }); + }, + + 'test json with broadcast flag': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.on('trigger broadcast', function () { + socket.broadcast.json.send([1, 2, 3]); + }); + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: [1, 2, 3] + , endpoint: '' + }); + + messages++; + ws1.finishClose(); + } + }); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: [1, 2, 3] + , endpoint: '' + }); + + messages++; + ws2.finishClose(); + } + }); + }); + + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('open', function () { + ws3.packet({ + type: 'event' + , name: 'trigger broadcast' + , endpoint: '' + }); + + setTimeout(function () { + ws3.finishClose(); + }, 50); + }); + + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + throw new Error('we shouldnt get a message here'); + } + }); + }); + }, + + 'test event with broadcast flag': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + socket.on('trigger broadcast', function () { + socket.broadcast.emit('hey', 'arnold'); + }); + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(2); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'hey' + , args: ['arnold'] + , endpoint: '' + }); + + messages++; + ws1.finishClose(); + } + }); + }); + + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'hey' + , args: ['arnold'] + , endpoint: '' + }); + + messages++; + ws2.finishClose(); + } + }); + }); + + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('open', function () { + ws3.packet({ + type: 'event' + , name: 'trigger broadcast' + , endpoint: '' + }); + + setTimeout(function () { + ws3.finishClose(); + }, 50); + }); + + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + throw new Error('we shouldnt get a message here'); + } + }); + }); + }, + + 'test message with broadcast flag and to()': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections == 1) { + socket.join('losers'); + } + + socket.on('trigger broadcast', function () { + socket.broadcast.to('losers').send('boom'); + }); + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(1); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'message' + , data: 'boom' + , endpoint: '' + }); + + messages++; + } + }); + + ws1.on('open', function () { + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + throw new Error('This socket shouldnt get a message'); + } + }); + + ws2.on('open', function () { + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('open', function () { + ws3.packet({ + type: 'event' + , name: 'trigger broadcast' + , endpoint: '' + }); + + setTimeout(function () { + ws1.finishClose(); + ws2.finishClose(); + ws3.finishClose(); + }, 50); + }); + + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + throw new Error('we shouldnt get a message here'); + } + }); + }); + }); + }); + }); + }); + }, + + 'test json with broadcast flag and to()': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections == 1) { + socket.join('losers'); + } + + socket.on('trigger broadcast', function () { + socket.broadcast.json.to('losers').send({ hello: 'world' }); + }); + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(1); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'json' + , data: { hello: 'world' } + , endpoint: '' + }); + + messages++; + } + }); + + ws1.on('open', function () { + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + throw new Error('This socket shouldnt get a message'); + } + }); + + ws2.on('open', function () { + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('open', function () { + ws3.packet({ + type: 'event' + , name: 'trigger broadcast' + , endpoint: '' + }); + + setTimeout(function () { + ws1.finishClose(); + ws2.finishClose(); + ws3.finishClose(); + }, 50); + }); + + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + throw new Error('we shouldnt get a message here'); + } + }); + }); + }); + }); + }); + }); + }, + + 'test event with broadcast flag and to()': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , cl3 = client(port) + , io = create(cl1) + , messages = 0 + , connections = 0 + , disconnections = 0; + + io.configure(function () { + io.set('close timeout', 0); + }); + + io.sockets.on('connection', function (socket) { + connections++; + + if (connections == 1) { + socket.join('losers'); + } + + socket.on('trigger broadcast', function () { + socket.broadcast.to('losers').emit('victory'); + }); + + socket.on('disconnect', function () { + disconnections++; + + if (disconnections == 3) { + messages.should.eql(1); + cl1.end(); + cl2.end(); + cl3.end(); + io.server.close(); + done(); + } + }); + }); + + cl1.handshake(function (sid) { + var ws1 = websocket(cl1, sid); + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + } else { + msg.should.eql({ + type: 'event' + , name: 'victory' + , args: [] + , endpoint: '' + }); + + messages++; + } + }); + + ws1.on('open', function () { + cl2.handshake(function (sid) { + var ws2 = websocket(cl2, sid); + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + } else { + throw new Error('This socket shouldnt get a message'); + }; + }); + + ws2.on('open', function () { + cl3.handshake(function (sid) { + var ws3 = websocket(cl3, sid); + ws3.on('open', function () { + ws3.packet({ + type: 'event' + , name: 'trigger broadcast' + , endpoint: '' + }); + + setTimeout(function () { + ws1.finishClose(); + ws2.finishClose(); + ws3.finishClose(); + }, 50); + }); + + ws3.on('message', function (msg) { + if (!ws3.connected) { + msg.type.should.eql('connect'); + ws3.connected = true; + } else { + throw new Error('we shouldnt get a message here'); + } + }); + }); + }); + }); + }); + }); + }, + + 'test accessing handshake data from sockets': function (done) { + var cl = client(++ports) + , io = create(cl) + , ws; + + io.sockets.on('connection', function (socket) { + (!!socket.handshake.address.address).should.be.true; + (!!socket.handshake.address.port).should.be.true; + socket.handshake.headers.host.should.equal('localhost'); + socket.handshake.headers.connection.should.equal('keep-alive'); + socket.handshake.time.should.match(/GMT/); + + socket.on('disconnect', function () { + setTimeout(function () { + ws.finishClose(); + cl.end(); + io.server.close(); + done(); + }, 10); + }); + + socket.disconnect(); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('message', function (msg) { + if (!ws.connected) { + msg.type.should.eql('connect'); + ws.connected = true; + } + }); + }); + }, + + 'test accessing the array of clients': function (done) { + var port = ++ports + , cl1 = client(port) + , cl2 = client(port) + , io = create(cl1) + , total = 2 + , ws1, ws2; + + io.sockets.on('connection', function (socket) { + socket.on('join ferrets', function () { + socket.join('ferrets'); + socket.send('done'); + }); + }); + + function check() { + io.sockets.clients('ferrets').should.have.length(1); + io.sockets.clients('ferrets')[0].should.be.an.instanceof(sio.Socket); + io.sockets.clients('ferrets')[0].id.should.equal(ws1.sid); + io.sockets.clients().should.have.length(2); + io.sockets.clients()[0].should.be.an.instanceof(sio.Socket); + io.sockets.clients()[0].id.should.equal(ws1.sid); + io.sockets.clients()[1].should.be.an.instanceof(sio.Socket); + io.sockets.clients()[1].id.should.equal(ws2.sid); + + ws1.finishClose(); + ws2.finishClose(); + cl1.end(); + cl2.end(); + io.server.close(); + done(); + }; + + cl1.handshake(function (sid) { + ws1 = websocket(cl1, sid); + ws1.sid = sid; + ws1.on('message', function (msg) { + if (!ws1.connected) { + msg.type.should.eql('connect'); + ws1.connected = true; + ws1.packet({ + type: 'event' + , name: 'join ferrets' + , endpoint: '' + }); + } else { + cl2.handshake(function (sid) { + ws2 = websocket(cl2, sid); + ws2.sid = sid; + ws2.on('message', function (msg) { + if (!ws2.connected) { + msg.type.should.eql('connect'); + ws2.connected = true; + check(); + } + }); + }); + } + }); + }); + }, + + 'test accessing handshake data from sockets on disconnect': function (done) { + var cl = client(++ports) + , io = create(cl) + , ws; + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + + (!!socket.handshake.address.address).should.be.true; + (!!socket.handshake.address.port).should.be.true; + socket.handshake.headers.host.should.equal('localhost'); + socket.handshake.headers.connection.should.equal('keep-alive'); + socket.handshake.time.should.match(/GMT/); + + setTimeout(function () { + ws.finishClose(); + cl.end(); + io.server.close(); + done(); + }, 10); + }); + + socket.disconnect(); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('message', function (msg) { + if (!ws.connected) { + msg.type.should.eql('connect'); + ws.connected = true; + } + }); + }); + }, + + 'test for intentional and unintentional disconnects': function (done) { + var cl = client(++ports) + , io = create(cl) + , calls = 0 + , ws; + + function close () { + cl.end(); + io.server.close(); + ws.finishClose(); + done(); + } + + io.configure(function () { + io.set('heartbeat interval', .05); + io.set('heartbeat timeout', .05); + io.set('close timeout', 0); + }); + + io.of('/foo').on('connection', function (socket) { + socket.on('disconnect', function (reason) { + reason.should.equal('packet'); + + if (++calls == 2) close(); + }); + }); + + io.of('/bar').on('connection', function (socket) { + socket.on('disconnect', function (reason) { + reason.should.equal('socket end'); + + if (++calls == 2) close(); + }); + }); + + cl.handshake(function (sid) { + var messages = 0; + ws = websocket(cl, sid); + ws.on('open', function () { + ws.packet({ + type: 'connect' + , endpoint: '/foo' + }); + ws.packet({ + type: 'connect' + , endpoint: '/bar' + }); + }); + + ws.on('message', function (packet) { + if (packet.type == 'connect') { + if (++messages === 3) { + ws.packet({ type: 'disconnect', endpoint:'/foo' }); + ws.finishClose(); + } + } + }); + }); + }, + + 'test socket clean up': function (done) { + var cl = client(++ports) + , io = create(cl) + , ws; + + io.sockets.on('connection', function (socket) { + var self = this + , id = socket.id; + + socket.on('disconnect', function () { + setTimeout(function () { + var available = !!self.sockets[id]; + + available.should.be.false; + ws.finishClose(); + cl.end(); + io.server.close(); + done(); + }, 10); + }); + + socket.disconnect(); + }); + + cl.handshake(function (sid) { + ws = websocket(cl, sid); + ws.on('message', function (msg) { + if (!ws.connected) { + msg.type.should.eql('connect'); + ws.connected = true; + } + }); + }); + }, + +}; diff --git a/NodeDrawing/node_modules/socket.io/test/transports.xhr-polling.test.js b/NodeDrawing/node_modules/socket.io/test/transports.xhr-polling.test.js new file mode 100644 index 0000000..df23241 --- /dev/null +++ b/NodeDrawing/node_modules/socket.io/test/transports.xhr-polling.test.js @@ -0,0 +1,2716 @@ + +/*! + * socket.io-node + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Test dependencies. + */ + +var sio = require('socket.io') + , should = require('./common') + , HTTPClient = should.HTTPClient + , parser = sio.parser + , ports = 15200; + +/** + * HTTPClient for xhr-polling transport. + */ + +function XHRPolling (port) { + HTTPClient.call(this, port); +}; + +/** + * Inhertis from HTTPClient. + */ + +XHRPolling.prototype.__proto__ = HTTPClient.prototype; + +/** + * Performs the handshake and expects the connect echo packet. + * + * @api public + */ + +XHRPolling.prototype.handshake = function (opts, fn) { + if ('function' == typeof opts) { + fn = opts; + opts = {}; + } + + var self = this; + + return this.get('/socket.io/{protocol}', opts, function (res, data) { + var parts = data.split(':'); + + if (opts.ignoreConnect) { + return fn && fn.apply(null, parts); + } + + // expect connect packet right after handshake + self.get( + '/socket.io/{protocol}/xhr-polling/' + parts[0] + , function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'connect', endpoint: '', qs: '' }); + + fn && fn.apply(null, parts); + } + ); + }); +}; + +/** + * Create client for this transport. + * + * @api public + */ + +function client (port) { + return new XHRPolling(port); +}; + +/** + * Test. + */ + +module.exports = { + + 'test handshake': function (done) { + var cl = client(++ports) + , io = create(cl); + + io.configure(function () { + io.set('close timeout', .05); + io.set('polling duration', 0); + }); + + function finish () { + cl.end(); + io.server.close(); + done(); + }; + + cl.handshake(function (sid) { + var total = 2; + + cl.get('/socket.io/{protocol}/xhr-polling/tobi', function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'error' + , reason: 'client not handshaken' + , endpoint: '' + , advice: 'reconnect' + }); + + --total || finish(); + }); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + --total || finish(); + }); + }); + }, + + 'test the connection event': function (done) { + var cl = client(++ports) + , io = create(cl) + , sid; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.id.should.eql(sid); + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + }); + }); + }, + + 'test the disconnection event after a close timeout': function (done) { + var cl = client(++ports) + , io = create(cl) + , sid; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.id.should.eql(sid); + + socket.on('disconnect', function () { + io.server.close(); + done(); + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + + setTimeout(function () { + cl.end(); + }, 10); + }); + }); + }, + + 'test the disconnection event when the client sends ?disconnect req': + function (done) { + var cl = client(++ports) + , io = create(cl) + , disconnected = false + , sid; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + disconnected = true; + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'disconnect', endpoint: '' }); + disconnected.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid + '/?disconnect'); + }); + }); + }, + + 'test the disconnection event booting a client': function (done) { + var cl = client(++ports) + , io = create(cl) + , forced = false; + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + io.server.close(); + done(); + }); + + cl.end(); + socket.disconnect(); + forced = true; + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'disconnect', endpoint: '' }); + + forced.should.be.true; + }); + }); + }, + + 'test the disconnection event with client disconnect packet': function (done) { + var cl = client(++ports) + , io = create(cl) + , sid; + + io.sockets.on('connection', function (client) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'disconnect' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + + client.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + }); + }); + }, + + 'test sending back data': function (done) { + var cl = client(++ports) + , io = create(cl); + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.send('woot'); + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, packs) { + packs.should.have.length(1); + packs[0].type.should.eql('message'); + packs[0].data.should.eql('woot'); + }); + }); + }, + + 'test sending a batch of messages': function (done) { + var cl = client(++ports) + , io = create(cl) + , sid; + + io.configure(function () { + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + var messages = 0; + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePayload([ + parser.encodePacket({ type: 'message', data: 'a' }) + , parser.encodePacket({ type: 'message', data: 'b' }) + , parser.encodePacket({ type: 'disconnect' }) + ]) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + + socket.on('message', function (data) { + messages++; + + if (messages == 1) + data.should.eql('a'); + + if (messages == 2) + data.should.eql('b'); + }); + + socket.on('disconnect', function () { + messages.should.eql(2); + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake({ ignoreConnect: true }, function (sessid) { + sid = sessid; + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].type.should.eql('connect'); + }); + }); + }, + + 'test message buffering between a response and a request': function (done) { + var cl = client(++ports) + , io = create(cl) + , messages = false + , tobi; + + io.configure(function () { + io.set('polling duration', .1); + io.set('close timeout', .2); + }); + + io.sockets.on('connection', function (socket) { + tobi = function () { + socket.send('a'); + socket.send('b'); + socket.send('c'); + }; + + socket.on('disconnect', function () { + messages.should.be.true; + + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + tobi(); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + msgs.should.have.length(3); + msgs[0].should.eql({ type: 'message', endpoint: '', data: 'a' }); + msgs[1].should.eql({ type: 'message', endpoint: '', data: 'b' }); + msgs[2].should.eql({ type: 'message', endpoint: '', data: 'c' }); + messages = true; + }); + }) + }); + }, + + 'test connecting to a specific endpoint': function (done) { + var cl = client(++ports) + , io = create(cl) + , connectMessage = false + , sid; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.of('/woot').on('connection', function (socket) { + connectMessage.should.be.true; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid); + + connectMessage = true; + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/woot' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + }); + }); + }, + + 'test that connecting doesnt connect to defined endpoints': function (done) { + var cl = client(++ports) + , io = create(cl) + , tobiConnected = false + , mainConnected = false + , sid; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + mainConnected = true; + + socket.on('disconnect', function () { + tobiConnected.should.be.false; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/tobi').on('connection', function () { + tobiConnected = true; + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid); + }); + }, + + 'test disconnecting a specific endpoint': function (done) { + var cl = client(++ports) + , io = create(cl) + , wootDisconnected = false + , mainDisconnected = false + , checked = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (data) { + data.should.eql('ferret'); + mainDisconnected.should.be.false; + wootDisconnected.should.be.true; + checked = true; + }); + + socket.on('disconnect', function () { + mainDisconnected = true; + checked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/woot').on('connection', function (socket) { + socket.on('disconnect', function () { + wootDisconnected = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function () { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/woot' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'disconnect', endpoint: '/woot' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'message', data: 'ferret' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + } + ); + }); + }); + }, + + 'test that disconnecting disconnects all endpoints': function (done) { + var cl = client(++ports) + , io = create(cl) + , aDisconnected = false + , bDisconnected = false; + + io.configure(function () { + io.set('polling duration', .2); + io.set('close timeout', .2); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + setTimeout(function () { + aDisconnected.should.be.true; + bDisconnected.should.be.true; + cl.end(); + io.server.close(); + done(); + }, 50); + }); + }); + + io.of('/a').on('connection', function (socket) { + socket.on('disconnect', function (msg) { + aDisconnected = true; + }); + }); + + io.of('/b').on('connection', function (socket) { + socket.on('disconnect', function (msg) { + bDisconnected = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/b' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + }); + }); + }, + + 'test messaging a specific endpoint': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = true + , aMessaged = false + , bMessaged = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql(''); + messaged = true; + }); + + socket.on('disconnect', function () { + messaged.should.be.true; + aMessaged.should.be.true; + bMessaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/a').on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql('a'); + aMessaged = true; + }); + }); + + io.of('/b').on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql('b'); + bMessaged = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'message', data: '' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'message', endpoint: '/a', data: 'a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/b' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'message', endpoint: '/b', data: 'b' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + }); + }); + }, + + 'test sending json from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , messages = 0 + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + s.json.send(['a', 'b', 'c']); + s.json.send({ + a: 'b' + , c: 'd' + }); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'json' + , data: ['a', 'b', 'c'] + , endpoint: '' + }); + msgs[1].should.eql({ + type: 'json' + , data: { + a: 'b' + , c: 'd' + } + , endpoint: '' + }); + }); + }) + }); + }, + + 'test sending json to the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , messages = 0; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .1); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (msg) { + messages++; + + if (messages == 1) { + msg.should.eql({ tobi: 'rocks' }); + } else if (messages == 2) { + msg.should.eql(5000); + } + }); + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'json' + , data: { tobi: 'rocks' } + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.equal('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'json' + , data: 5000 + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.equal('1'); + } + ); + } + ); + }); + }); + }, + + 'test emitting an event from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + s.emit('tobi is playing'); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'event' + , name: 'tobi is playing' + , endpoint: '' + , args: [] + }); + }); + }); + }); + }, + + 'test emitting an event with data from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + s.emit('edwald', { woot: 'woot' }, [1, 2, 3]); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'event' + , name: 'edwald' + , endpoint: '' + , args: [{ woot: 'woot' }, [1, 2, 3]] + }); + }); + }); + }); + }, + + 'test emitting an event to the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('jane', function (a, b, c) { + messaged = true; + }); + + socket.on('disconnect', function () { + messaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'event' + , name: 'jane' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.equal('1'); + } + ); + }); + }); + }, + + 'test emitting an event to the server with data': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('woot', function (a, b, c) { + a.should.eql('a'); + b.should.eql(2); + c.should.eql([1, 2]); + + messaged = true; + }); + + socket.on('disconnect', function () { + messaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'event' + , name: 'woot' + , args: ['a', 2, [1, 2]] + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.equal('1'); + } + ); + }); + }); + }, + + 'test sending undeliverable volatile messages': function (done) { + var cl = client(++ports) + , io = create(cl) + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + s.volatile.send('woooot'); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + }); + }); + }); + }, + + 'test sending undeliverable volatile json': function (done) { + var cl = client(++ports) + , io = create(cl) + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + s.volatile.json.send('woooot'); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + }); + }); + }); + }, + + 'test sending undeliverable volatile events': function (done) { + var cl = client(++ports) + , io = create(cl) + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + s.volatile.emit('woooot'); + + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + }); + }); + }); + }, + + 'test sending deliverable volatile messages': function (done) { + var cl = client(++ports) + , io = create(cl) + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'message' + , data: 'woooot' + , endpoint: '' + }); + }); + + setTimeout(function () { + s.volatile.send('woooot'); + }, 10); + }); + }, + + 'test sending deliverable volatile json': function (done) { + var cl = client(++ports) + , io = create(cl) + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'json' + , data: 5 + , endpoint: '' + }); + }); + + setTimeout(function () { + s.volatile.json.send(5); + }, 10); + }); + }, + + 'test sending deliverable volatile events': function (done) { + var cl = client(++ports) + , io = create(cl) + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'event' + , name: 'tobi' + , args: [] + , endpoint: '' + }); + }); + + setTimeout(function () { + s.volatile.json.emit('tobi'); + }, 10); + }); + }, + + 'test automatic acknowledgements sent from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , received = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql('woot'); + received = true; + }); + + socket.on('disconnect', function () { + received.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'message' + , data: 'woot' + , id: 1 + , endpoint: '' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'ack' + , ackId: 1 + , endpoint: '' + , args: [] + }); + } + ); + } + ); + }); + + }); + }, + + 'test manual data acknowledgement sent from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , acknowledged = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (data, fn) { + data.should.eql('tobi'); + fn('woot'); + acknowledged = true; + }); + + socket.on('disconnect', function () { + acknowledged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'ack' + , args: ['woot'] + , endpoint: '' + , ackId: '3' + }); + }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'message' + , data: 'tobi' + , ack: 'data' + , id: '3' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + }); + }, + + 'test automatic acknowledgements sent from the client': function (done) { + var cl = client(++ports) + , io = create(cl) + , acknowledged = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.send('aaaa', function () { + acknowledged = true; + }); + + socket.on('disconnect', function () { + acknowledged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'message' + , id: '1' + , data: 'aaaa' + , ack: true + , endpoint: '' + }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'ack' + , ackId: '1' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + }); + }); + }, + + 'test automatic ack with event sent from the client': function (done) { + var cl = client(++ports) + , io = create(cl) + , acked = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.emit('woot', 1, 2, '3', function () { + acked = true; + }); + + socket.on('disconnect', function () { + acked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'event' + , name: 'woot' + , args: [1, 2, '3'] + , id: '1' + , ack: true + , endpoint: '' + }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'ack' + , ackId: '1' + , args: [] + , endpoint: '' + }) + ); + }); + }); + }, + + 'test manual data ack with event sent from the client': function (done) { + var cl = client(++ports) + , io = create(cl) + , acked = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.emit('woot', 1, 2, '3', function (a) { + a.should.eql('1'); + acked = true; + }); + + socket.on('disconnect', function () { + acked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'event' + , name: 'woot' + , args: [1, 2, '3'] + , id: '1' + , ack: 'data' + , endpoint: '' + }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'ack' + , ackId: '1' + , args: ['1'] + , endpoint: '' + }) + ); + }); + }); + }, + + 'test endpoint sending json from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , received = false;; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + received.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/chrislee').on('connection', function (socket) { + socket.json.send([1, 2, { 3: 4 }]); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + msgs[1].should.eql({ + type: 'json' + , data: [1, 2, { 3: 4 }] + , endpoint: '/chrislee' + }); + + received = true; + } + ); + } + ); + }); + }); + }, + + 'test endpoint sending json to the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false + , subMessaged = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (msg) { + messaged = true; + }); + + socket.on('disconnect', function () { + messaged.should.be.false; + subMessaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/a').on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql(['a', 'b', { c: 'd' }]); + subMessaged = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'json' + , endpoint: '/a' + , data: ['a', 'b', { c: 'd' }] + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + }); + }); + }, + + 'test endpoint emitting an event from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , received = false;; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + received.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/chrislee').on('connection', function (socket) { + socket.emit('tj'); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + msgs[1].should.eql({ + type: 'event' + , name: 'tj' + , args: [] + , endpoint: '/chrislee' + }); + + received = true; + } + ); + } + ); + }); + }); + }, + + 'test endpoint emitting an event with data from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , received = false;; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('disconnect', function () { + received.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/chrislee').on('connection', function (socket) { + socket.emit('tj', 1, 2, 3, 4); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + msgs[1].should.eql({ + type: 'event' + , name: 'tj' + , args: [1, 2, 3, 4] + , endpoint: '/chrislee' + }); + + received = true; + } + ); + } + ); + }); + }); + }, + + 'test endpoint emitting an event to the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false + , subMessaged = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (msg) { + messaged = true; + }); + + socket.on('disconnect', function () { + messaged.should.be.false; + subMessaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/a').on('connection', function (socket) { + socket.on('tj', function () { + subMessaged = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'event' + , name: 'tj' + , endpoint: '/a' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + }); + }); + }, + + 'test endpoint emitting an event to the server with data': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false + , subMessaged = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.on('message', function (msg) { + messaged = true; + }); + + socket.on('disconnect', function () { + messaged.should.be.false; + subMessaged.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + io.of('/a').on('connection', function (socket) { + socket.on('tj', function (ferret, age) { + ferret.should.eql('tobi'); + age.should.eql(23); + subMessaged = true; + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/a' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'event' + , name: 'tj' + , endpoint: '/a' + , args: ['tobi', 23] + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + }); + }); + }, + + 'test endpoint sending undeliverable volatile messages': function (done) { + var cl = client(++ports) + , io = create(cl) + , empty = false + , s; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.of('/chrislee').on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + empty.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + s.volatile.send('woot'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.length.should.eql(1); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + empty = true; + } + ); + } + ); + }); + }); + }, + + 'test endpoint sending undeliverable volatile json': function (done) { + var cl = client(++ports) + , io = create(cl) + , empty = false + , s; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.of('/chrislee').on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + empty.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + s.volatile.json.send(15); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.length.should.eql(1); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + empty = true; + } + ); + } + ); + }); + }); + }, + + 'test endpoint sending undeliverable volatile events': function (done) { + var cl = client(++ports) + , io = create(cl) + , empty = false + , s; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.of('/chrislee').on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + empty.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + s.volatile.json.emit('woot'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.length.should.eql(1); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + empty = true; + } + ); + } + ); + }); + }); + }, + + 'test endpoint sending deliverable volatile messages': function (done) { + var cl = client(++ports) + , io = create(cl) + , received = false + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.of('/chrislee').on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + received.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'message' + , data: 'edwald' + , endpoint: '/chrislee' + }); + + received = true; + } + ); + + setTimeout(function () { + s.volatile.send('edwald'); + }, 20); + } + ); + } + ); + }); + }); + }, + + 'test endpoint sending deliverable volatile json': function (done) { + var cl = client(++ports) + , io = create(cl) + , received = false + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.of('/chrislee').on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + received.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'json' + , data: 152 + , endpoint: '/chrislee' + }); + + received = true; + } + ); + + setTimeout(function () { + s.volatile.json.send(152); + }, 20); + } + ); + } + ); + }); + }); + }, + + 'test endpoint sending deliverable volatile events': function (done) { + var cl = client(++ports) + , io = create(cl) + , received = false + , s; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.of('/chrislee').on('connection', function (socket) { + s = socket; + + socket.on('disconnect', function () { + received.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/chrislee' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/chrislee' + , qs: '' + }); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + msgs.should.have.length(1); + msgs[0].should.eql({ + type: 'event' + , name: 'woooo' + , args: [[1, 2]] + , endpoint: '/chrislee' + }); + + received = true; + } + ); + + setTimeout(function () { + s.volatile.emit('woooo', [1, 2]); + }, 20); + } + ); + } + ); + }); + }); + }, + + 'test endpoint automatic acks sent from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false + , acked = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.of('/tobi').on('connection', function (socket) { + socket.on('message', function (msg) { + msg.should.eql('woot'); + messaged = true; + }); + + socket.on('disconnect', function () { + acked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/tobi' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'message' + , id: '3' + , data: 'woot' + , endpoint: '/tobi' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/tobi' + , qs: '' + }); + msgs[1].should.eql({ + type: 'ack' + , ackId: '3' + , endpoint: '/tobi' + , args: [] + }); + + acked = true; + } + ); + } + ); + } + ); + }); + }); + }, + + 'test endpoint manual data ack sent from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false + , acked = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.of('/tobi').on('connection', function (socket) { + socket.on('message', function (msg, fn) { + msg.should.eql('woot'); + fn(); + messaged = true; + }); + + socket.on('disconnect', function () { + acked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/tobi' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'message' + , id: '3' + , data: 'woot' + , ack: 'data' + , endpoint: '/tobi' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/tobi' + , qs: '' + }); + msgs[1].should.eql({ + type: 'ack' + , ackId: '3' + , args: [] + , endpoint: '/tobi' + }); + + acked = true; + } + ); + } + ); + } + ); + }); + }); + }, + + 'test endpoint manual data event ack sent from the server': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false + , acked = false; + + io.configure(function () { + io.set('polling duration', 0); + io.set('close timeout', .05); + }); + + io.of('/tobi').on('connection', function (socket) { + socket.on('woot', function (msg, fn) { + msg.should.eql(1); + fn('aaaa'); + messaged = true; + }); + + socket.on('disconnect', function () { + acked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, data) { + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/tobi' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'event' + , id: '3' + , name: 'woot' + , ack: 'data' + , args: [1] + , endpoint: '/tobi' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/tobi' + , qs: '' + }); + msgs[1].should.eql({ + type: 'ack' + , ackId: '3' + , args: ['aaaa'] + , endpoint: '/tobi' + }); + + acked = true; + } + ); + } + ); + } + ); + }); + }); + }, + + 'test endpoint acknowledgements sent from the client': function (done) { + var cl = client(++ports) + , io = create(cl) + , acked = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.of('/woot').on('connection', function (socket) { + socket.send('aaa', function () { + acked = true; + }); + + socket.on('disconnect', function () { + acked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.eql(200); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/woot' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/woot' + , qs: '' + }); + msgs[1].should.eql({ + type: 'message' + , data: 'aaa' + , endpoint: '/woot' + , id: '1' + , ack: true + }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'ack' + , ackId: '1' + , endpoint: '/woot' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + } + ); + }); + }); + }, + + 'test endpoint manual data event acks sent from the client': function (done) { + var cl = client(++ports) + , io = create(cl) + , acked = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.of('/rapture').on('connection', function (socket) { + socket.emit('woot', 'a', function (a, b, c) { + a.should.eql(5); + b.should.eql('hello'); + c.should.eql([1, 2, 3]); + + acked = true; + }); + + socket.on('disconnect', function () { + acked.should.be.true; + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, msgs) { + res.statusCode.should.equal(200); + msgs.should.have.length(1); + msgs[0].should.eql({ type: 'noop', endpoint: '' }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ type: 'connect', endpoint: '/rapture' }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, msgs) { + res.statusCode.should.eql(200); + msgs.should.have.length(2); + msgs[0].should.eql({ + type: 'connect' + , endpoint: '/rapture' + , qs: '' + }); + msgs[1].should.eql({ + type: 'event' + , id: '1' + , name: 'woot' + , args: ['a'] + , ack: 'data' + , endpoint: '/rapture' + }); + + cl.post( + '/socket.io/{protocol}/xhr-polling/' + sid + , parser.encodePacket({ + type: 'ack' + , ackId: '1' + , args: [5, 'hello', [1, 2, 3]] + , endpoint: '/rapture' + }) + , function (res, data) { + res.statusCode.should.eql(200); + data.should.eql('1'); + } + ); + } + ); + } + ); + }); + }); + }, + + 'test CORS': function (done) { + var cl = client(++ports) + , io = create(cl) + , messaged = false; + + io.configure(function () { + io.set('polling duration', .05); + io.set('close timeout', .05); + }); + + io.sockets.on('connection', function (socket) { + socket.send('woot'); + + socket.on('message', function (msg) { + msg.should.equal('woot'); + messaged = true; + }); + + socket.on('disconnect', function () { + cl.end(); + io.server.close(); + done(); + }); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, { + headers: { + Origin: 'http://localhost:3500' + } + }, function (res, packs) { + var headers = res.headers; + + headers['access-control-allow-origin'].should.equal('*'); + should.strictEqual(headers['access-control-allow-credentials'], undefined); + + packs.should.have.length(1); + packs[0].type.should.eql('message'); + packs[0].data.should.eql('woot'); + + cl.post('/socket.io/{protocol}/xhr-polling/' + sid, parser.encodePacket({ + type: 'message' + , data: 'woot' + }), { + headers: { + Origin: 'http://localhost:3500' + , Cookie: 'woot=woot' + } + }, function (res, data) { + var headers = res.headers; + headers['access-control-allow-origin'].should.equal('*'); + headers['access-control-allow-credentials'].should.equal('true'); + + data.should.equal('1'); + }); + }); + }); + }, + + 'test emitting to closed clients': function (done) { + var cl = client(++ports) + , cl2 = client(ports) + , io = create(cl) + , connections = 0; + + io.configure(function () { + io.set('close timeout', .1); + }); + + io.sockets.on('connection', function (socket) { + socket.send('a'); + }); + + cl.handshake(function (sid) { + cl.get('/socket.io/{protocol}/xhr-polling/' + sid, function (res, packs) { + res.statusCode.should.equal(200); + packs.should.have.length(1); + packs[0].should.eql({ type: 'message', endpoint: '', data: 'a' }); + + cl2.handshake(function (sid2) { + cl2.get( + '/socket.io/{protocol}/xhr-polling/' + sid2 + , function (res, packs) { + res.statusCode.should.equal(200); + packs.should.have.length(1); + packs[0].should.eql({ type: 'message', endpoint: '', data: 'a' }); + + io.sockets.emit('woot', 'b'); + + var total = 2; + + cl.get( + '/socket.io/{protocol}/xhr-polling/' + sid + , function (res, packs) { + res.statusCode.should.equal(200); + packs.should.have.length(1); + packs[0].should.eql({ + type: 'event' + , endpoint: '' + , name: 'woot' + , args: ['b'] + }); + + --total || finish(); + } + ); + + cl2.get( + '/socket.io/{protocol}/xhr-polling/' + sid2 + , function (res, packs) { + res.statusCode.should.equal(200); + packs.should.have.length(1); + packs[0].should.eql({ + type: 'event' + , endpoint: '' + , name: 'woot' + , args: ['b'] + }); + + --total || finish(); + } + ); + + function finish () { + cl.end(); + cl2.end(); + io.server.close(); + done(); + }; + } + ); + }); + + }); + }); + } + +}; diff --git a/NodeDrawing/package.json b/NodeDrawing/package.json new file mode 100644 index 0000000..7d116a0 --- /dev/null +++ b/NodeDrawing/package.json @@ -0,0 +1,9 @@ +{ + "name": "NodeDrawing" + , "version": "0.0.1" + , "private": true + , "dependencies": { + "express": "2.3.12" + , "socket.io": "0.7.8" + } +} \ No newline at end of file diff --git a/NodeDrawing/public/stylesheets/style.css b/NodeDrawing/public/stylesheets/style.css new file mode 100644 index 0000000..30e047d --- /dev/null +++ b/NodeDrawing/public/stylesheets/style.css @@ -0,0 +1,8 @@ +body { + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; +} + +a { + color: #00B7FF; +} \ No newline at end of file diff --git a/NodeDrawing/views/index.jade b/NodeDrawing/views/index.jade new file mode 100644 index 0000000..c9c35fa --- /dev/null +++ b/NodeDrawing/views/index.jade @@ -0,0 +1,2 @@ +h1= title +p Welcome to #{title} \ No newline at end of file diff --git a/NodeDrawing/views/layout.jade b/NodeDrawing/views/layout.jade new file mode 100644 index 0000000..1a36941 --- /dev/null +++ b/NodeDrawing/views/layout.jade @@ -0,0 +1,6 @@ +!!! +html + head + title= title + link(rel='stylesheet', href='/stylesheets/style.css') + body!= body \ No newline at end of file